Two-factor SSH using oathtool on Ubuntu 18.04

July 16, 2018
Last modified June 20, 2019

I’ve been using the Google Authenticator PAM Module for years. It works great, and is easy to set up. But, I generally try to stay away from all things Google, so I wanted to set up two-factor ssh using something else.

After a bit of googling (…), I found OATH Toolkit. Reading their documentation, it seems rather easy to set up. Also, this blog has a nice TL;DR of the setup. I’ve pretty much followed that, and added a few bits.

Setting up oathtool

# Install oathtool.
sudo apt install oathtool libpam-oath

export HEX_SECRET=$(head -15 /dev/urandom | sha1sum | cut -b 1-30)

oathtool --verbose --totp $HEX_SECRET --digits=8

# Type in the Base32-secret on your phone

sudo touch /etc/users.oath
sudo chmod 0600 /etc/users.oath

# Running subshell so we can send output to file with sudo-permissions
sudo /bin/bash -c "echo HOTP/T30 $USER - $HEX_SECRET \ >> /etc/users.oath"

# Unset your secret

Setting up an access-list for two-factor

Now, I want to be able to define who I require two-factor for, and from where I require it. I have a couple of hosts that I trust, where I can log in from in case I lose my two-factor.

Create /etc/security/login_token.conf. My file has the following contents:

# Do not require two-factor from here:
+ : dennis :

# lolnope don't need two-factor at all
+ : lolnope : ALL

# Demand two-factor from everywhere and everyone else
- : ALL : ALL

See man 5 access.conf for details on the format (link).

Setting up libpam-oath

Add the following to the top of /etc/pam.d/sshd:

# Exceptions from two-factor
auth    [success=1 default=ignore] accessfile=/etc/security/login_token.conf
# Two-factor
auth required usersfile=/etc/users.oath


Now all we need to do is to enable two-facor in sshd_config. Set ChallengeResponseAuthentication to yes in /etc/ssh/sshd_config. Now we can restart ssh, and test it!


This is what it should look like when logging in:

$ # I use ssh-keys, do I need to auth without them
$ ssh -o PubkeyAuthentication=no dennis@host
One-time password (OATH) for `dennis':

And, when logging in from one of the hosts I’ve defined in /etc/security/login_token.conf, I’m not asked about the OTP!