IT Blog


Two Factor SSH with Google Authenticator

Last week, Google enabled two factor authentication for everyone. This article explains how to install and configure Google Authenticator in conjunction with SSH for two factor authentication. Two-factor authentication relies on something you know (a password) and something you have (your phone).

Update: I have posted another article describing this same implementation with a Yubikey.
You can use this existing implementation and Google Authenticator application with SSH via an included PAM in the Google Authenticator open source application.

Download the Google Authenticator application

First, download and install Google Authenticator on your Iphone/Android/Blackberry.

Compile, install, configure Google authenticator PAM

You may need a few dependencies. On RHEL 5 I was missing ‘pam-devel’.

$ hg clone google-authenticator/
$ cd google-authenticator/libpam/
$ make
$ sudo make install
$ sudo vi /etc/pam.d/sshd

Add the following line to the beginning of /etc/pam.d/sshd:
auth required
You also need to update /etc/ssh/sshd_config and add/update:
ChallengeResponseAuthentication yes

Setup your user to require two-factor authentication

As a user, you can now run ‘google-authenticator’. This will generate a secret key, and add a file to your home directory that the newly installed PAM uses.

$ google-authenticator|0&cht=qr&chl=otpauth://totp/
Your new secret key is: AAAAAAAAAAAAAAAA
Your verification code is 123123
Your emergency scratch codes are:
Do you want me to update your "~/.google_authenticator" file (y/n) y
Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

Note: The emergency scratch codes are one-time use verification codes in the event your phone is unavailable.

Configure this new secret key in Google Authenticator

In your Google Authenticator application on your phone, add this new secret key that was generated in the previous step. Note, a URL is also displayed, that can be scanned from your Google Authenticator application.

Wrapping up the setup

You will now need to restart SSH for the pam/ssh changes to activate.
At this point, you will want to stay logged into the server while you test in another shell.


Test that two-factor authentication is working.

$ ssh
Verification code:
[user@host ~]$

Enter the verification code as shown on your phone.

Your SSH sessions are now protected with two factor authentication

Running Linux Servers?

We provide 24×7 monitoring and response, proactive updates, and more. Priced per server, per month. Give us a call at 888-877-7118 or click here for further detail.

36 thoughts on “Two Factor SSH with Google Authenticator”

  1. Can this be made to work in combination with public key login? I’ve given it a try following the steps above, but I’m not being prompted for the OTP.

    1. I don’t think this will work in combination with a public key. PubkeyAuthentication overrides the requirement for the auth PAM methods and would likely require a patch for OpenSSH.
      I may be wrong, and would be interested in hearing if anyone knows how to make this work with PubKeyAuthentication.

  2. Works great on Ubuntu Server 10.04 LTS. Required packages “mercurial” (for hg) and “libpam0g-dev” to build the PAM modules.

  3. I’ve set this up on several Linux workstations and servers, some of which I also use ssh keys with. To my knowledge, the keys overwrite the need for the 2FA, which doesn’t bother me, since I’m more worried about intruders from outside versus intruders from what I consider trusted boxes (which they, themselves, are set up with 2FA, so in theory, barring a security hole, they shouldn’t get access to anyway).
    One of the bugs I’ve encountered (and I don’t know if it’s fixed yet) is that if you have a server and you want to make 2FA optional, the original code would not allow people who didn’t have a .google_authenticator file to log in, even if their password was correct. The issue was/is fixed with the patch found
    Also, I had tried this on a server with AFS….after applying the patch, if the user was set up for GA, then they could log in as expected. However, if a user was not set up for GA, they could log in, but wouldn’t receive their AFS token. I don’t know if there’s a workaround for that….
    But, all in all, I love this and have it set up to not only protect ssh, but initial log in and when my screensaver locks on my workstation at work.

  4. RCDevs OpenOTP also has a nice interface and full blown server platform with RADIUS, SOAP and PAM and Google Authenticator.
    It works with LDAP acounts. It’s very convenient for a PAM-LDAP + Two-factor with GA.
    Found it here :

  5. Awesome! I had to make two changes to my sshd_config, from what they were to the following:
    PubkeyAuthentication no
    UsePAM yes
    Once changed it worked perfectly.

    1. You’re able to select if you want to use: SMS; phone call; or application code generation.

  6. I get this after cloning the repository:
    $ hg clone google-authenticator/
    warning: certificate for can’t be verified (Python too old)
    requesting all changes
    adding changesets
    adding manifests
    adding file changes
    added 83 changesets with 437 changes to 315 files
    updating to branch default
    abort: No such file or directory

  7. Okay, I’m running into problems installing this on Ubuntu 11.04. The other website I linked to only works for 10.04 and I can’t get your instructions to work. Here is my complete build log:

    ~/google-authenticator/libpam$ make
    gcc --std=gnu99 -Wall -O2 -g -fPIC -c -o google-authenticator.o google-authenticator.c
    gcc --std=gnu99 -Wall -O2 -g -fPIC -c -o base32.o base32.c
    gcc --std=gnu99 -Wall -O2 -g -fPIC -c -o hmac.o hmac.c
    gcc --std=gnu99 -Wall -O2 -g -fPIC -c -o sha1.o sha1.c
    gcc -g -o google-authenticator google-authenticator.o base32.o hmac.o sha1.o
    google-authenticator.o: In function `displayQRCode':
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:154: undefined reference to `dlopen'
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:166: undefined reference to `dlsym'
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:168: undefined reference to `dlsym'
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:253: undefined reference to `dlclose'
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:156: undefined reference to `dlopen'
    collect2: ld returned 1 exit status
    make: *** [google-authenticator] Error 1

  8. Looks like the Makefile isn’t linking with libdl correctly. You could try changing this line:
    google-authenticator: google-authenticator.o base32.o hmac.o sha1.o
    $(CC) -g $(DEF_LDFLAGS) $(shell [ -f /usr/lib/ ] &&
    echo ” -ldl”) -o $@ $+
    to look like this instead:
    google-authenticator: google-authenticator.o base32.o hmac.o sha1.o
    $(CC) -g $(DEF_LDFLAGS) -ldl -o $@ $+
    That should force it to add ‘-ldl’ to the link.

  9. I know pconwell’s problem is over a month old, but in the interest of possibly helping someone else with the same issue, I’ll post what worked for me.
    I got the same error messages in my build and traced it to the fact that I am using a 64-bit version of CentOS. That means the libraries are in a different location. The offending library reference in the Makefile is /usr/lib/ On my system they are located in /usr/lib64 but yours may be different so try to track down where it is first.
    All I needed to be do was to edit the Makefile and replace any occurrence of /usr/lib/ with /usr/lib64/
    I don’t have the link, but someone has submitted this issue to the Authenticator project as a bug, so hopefully it will be fixed someday soon.

  10. @pconwell:
    Looks like you’re not linking the binary in with the dynamic linking loader library,*.
    Try modifying the last compile command to include “-ldl”, eg:
    gcc -g -o google-authenticator google-authenticator.o base32.o hmac.o sha1.o -ldl

  11. Do you think after Google deploy that apps, they will charge money to us?
    Now they can free, but really don’t know in the future.
    And they can access our server, everybody already thinking that!
    Anyway, it ‘s great, like OTP in Ebanking… HEHEHE!

  12. If you get
    pam_google_authenticator.c:41:34: error: security/pam_modules.h: No such file or directory
    pam_google_authenticator.c:65: error: expected declaration specifiers or ‘…’ before ‘pam_handle_t’

    apt-get install libpam0g-dev

  13. Just another tip this can be applied on the Mac side as well. You just need to move the pam for Google into the proper spot.
    By default it will place it in /usr/lib/
    Move into /usr/lib/pam/
    Works great and thats for the article.

  14. If you dont fancy Google having your userid and secret, then dont use that URL. Instead, enter the secret directly into the google-authenticator application on your smartphone.

  15. With regards to the SSH Key issue: I think this is by design and not a bug.
    SSH Key Login already *is* two-factor authentication if done according to best practice:
    1. Something you have – your encrypted SSH privkey
    2. Something you know – the passphrase für said privkey
    Thus, using the same factor again (something you have – totp token) does not increase effective security because you still only have two factors.
    In addition to remote logins via SSH, you can also use the PAM module to protect su. Just insert the line
    auth required
    in /etc/pam.d/su
    I don’t think there are repercussions for cron etc., but I might be wrong. It works fine on my test machine, though.
    I didn’t test it, but this should also work for sudo, which is obviously a nice-to-have for Ubuntu users.

  16. Don’t you think this kind of auth is very weak because of the emergency scratch codes ?
    How can you prevent a brute force attack on this ?

  17. This works with the package ‘libpam-google-authenticator’ in the Debian testing repo. All that’s required are the lines in /etc/ssh/sshd_config and /etc/pam.d/sshd, and it just works. If a public key is available then it will be used in preference to the Google Authenticator code.

  18. @portblanc
    There’s an option to enable rate-limiting, which “limits attackers to no more than 3 login attempts every 30s”. That means it would take over 31 years to test all possibilities of the 8 digit backup codes. And you would still have to brute force the SSH password (and the username, since root login should be disabled) as well. You should also have something like fail2ban – – running on your server.

Comments are closed.