I recently bought a U2F Zero, an $8.00 open source U2F (Universal 2nd Factor) hardware key.
After the initial setup of the U2F Zero (hint: there was none), I immediately wondered how I could enable it as a required second factor when logging into my Mac.
After a bit of browsing on Yubico's site and a couple of blogs, I didn't find a solid step-by-step tutorial on how to set this up that fully described the process and the different configurations. So here we are.
Note: These instructions apply for any U2F token, not just the U2F Zero or YubiKey devices.
If you're feeling dangerous (and I really do mean that), you can skip to the very end and just see which commands to run.
The U2F Zero is an open source DIY (or purchase pre-built from Amazon) hardware token that supports U2F (Univeral 2nd Factor) authentication. At $8.00, it's hard to beat the price, and similar products like the various YubiKeys aren't open source, which is a minor inconvenience for some and a dealbreaker for others.
You have the option of either purchasing it pre-assembled from Amazon or building it yourself. While I always enjoy soldering, the programmer alone is around $35, so unless you're going to build quite a few, you might be best off just buying them pre-built.
Enabling 2FA for OS X
Note: I'm doing this on macOS Sierra (10.12), but this should work on any recent version of OS X.
Basically I am trying to achieve the following: when logging in either after a restart or upon waking from sleep, I would like to require a U2F token as a second authentication factor, in addition to my password.
The process is actually extremely simple, and boils down to:
- Install the
- Generate the Authorization Mapping File for your key(s)
- Edit the system configuration files to enable U2F authentication
pam-u2f module is easiest with Homebrew, in which case a simple
brew install pam-u2f
If you're not using Homebrew on OS X (seriously?), you can build it from source following the instructions here. You will also need
automake and friends, and also
In either case, you will end up with a shared library called
pam_u2f.so. If you installed via Homebrew (be sure to check the version since the path will change) it will be located at
To make the configuration step easier, you can symlink the Homebrew library or copy the library you built into
cd /usr/lib/pam sudo ln -s /usr/local/Cellar/pam-u2f/1.0.4/lib/pam/pam_u2f.so # Or copy if you built it yourself
Note: You will get an
Operation not permittedmessage on OS X El Capitan or macOS Sierra, since you must disable System Integrity Protection to have write access to anything in
/usr/local. You can disable SIP by booting into recovery mode (⌘ + R) and then opening a Terminal and executing
If you decide not to disable SIP or just not to link or copy into
/usr/lib/pam, you can also just provide the full path to the
pam_u2f.so file in the configuration files later.
2. Authorization Mapping Files
In order for the module to know which U2F token to accept the challenge response from and authenticate with, you must store some information about your token. Specifically, you must create what is called an Authorization Mapping File, which contains a list of token pairs consisting of the key handles and the public keys.
More information on these files can be found here.
To generate this file, you can use the
pamu2fcfg utility which is installed with the
pam-u2f recipe on Homebrew or can also be built manually.
Insert your U2F token and then open a Terminal and run
Note: If you want to be verbose about the username for the token you can add the
If the device is inserted correctly, the colour of the light on the U2F Zero will change, prompting you to press the button to complete the challenge response. If everything worked you will see some output on the screen consisting of
<username>:<key handle>,<public key>\n
I'm going to place this in a file called
~/.config/u2f/keys, but you can place it anywhere. To directly output to the file:
# Create the directory if it doesn't exist mkdir -p ~/.config/u2f # Use >> if you want to append, or a single > if you want to rewrite the file pamu2fcfg > ~/.config/u2f/keys
You'll need to specify this location in the PAM configuration files, unless you place it in the file
~/.config/Yubico/u2f_keys, which is the default search location.
Multiple U2F Tokens
To use multiple tokens under the same user on the same machine, you just need to concatenate the second token's key information to the mapping file.
With one user and two tokens, the mapping file should look like:
<username>:<key handle 1>,<public key 1>:<key handle 2>,<public key 2>
Thankfully, the PAM U2F config tool includes an option (
-n) to leave off the username, so in the simple case of one user and two tokens you can just do
pamu2fcfg -n >> ~/.config/u2f/keys
with the second token.
If, however, you wanted to add a second token but for a different user, you would just add a separate line with the output right from
pamu2fcfg, no modification necessary.
For multiple users and/or tokens the mapping file could look like:
<username 1>:<key handle 1>,<public key 1>:<key handle 2>,<public key 2> <username 2>:<key handle 3>,<public key 3>:<key handle 2>,<public key 2>
In that example, both users have a unique token (keys
3) and also share a token (key
3. PAM Configuration Files
The PAM configuration files are located at
You will see a list of configuration files for various authentication modules here. Of these files, the
authorization files are of particular interest to us.
Note: In these steps it is extremely important to use the
sufficientkeyword and not the
requiredkeyword when first configuring these. This gives you the opportunity to test it out and verify that you can correctly use your U2F token to log in.
Open up the
screensaver file (with
sudo, of course) and add a line consisting of:
auth sufficient <path to pam_u2f.so> authfile=<path to mapping file>
Using the full Homebrew path and placing my authorization mapping file under
~/.config/u2f/keys, my line looks like:
auth sufficient /usr/local/Cellar/pam-u2f/1.0.4/lib/pam/pam_u2f.so authfile=/Users/joe/.config/u2f/keys
Note: You cannot perform shell expansions (e.g.
~) here so give the full path.
If you symlinked or installed directly into
/usr/lib/pam, and if you created your mapping file under
~/.config/Yubico/u2f_keys, you can simply use:
auth sufficient pam_u2f.so
Then save and exit. Make sure you're configured to require a password immediately after going to sleep, and then tell your Mac to go to sleep.
Upon waking, insert your U2F token and then type your password. After entering the password, it should pause and the light on your U2F Zero should change colours. Et voilà! Press the button to complete the challenge response and you should be successfully logged in with your U2F as a second factor!
You can now perform the next step by adding the same line to the
authorization file, and then log out and back in to test.
Since we chose
sufficient for the test, if you don't have your token inserted when you type your password, it will log in without asking for it. To require your token in addition to your password for true 2FA, simply change the
sufficient keyword to
required in the
Note: It is a very good idea to first try the
requiredconfiguration with the
screensaverfile only, since if something goes wrong, you can still authenticate via the normal login screen without your token.
As mentioned, be careful with requiring the token. If you lose your token, you may be totally locked out of your Mac. One solution to this is to buy two tokens and add both of them to your authorization mapping file. Then store that second token away for safe keeping.
If you really truly don't think you need to read about what it is that you're doing, you can achieve all of this by just running the following commands:
# Install PAM U2F Module brew install pam-u2f # Generate a new authorization mapping file mkdir -p ~/.config/u2f # >>> Insert U2F Token pamu2fcfg > ~/.config/u2f/keys # >>> Press button on U2F token # >>> Remove token # >>> Insert second U2F token (if you have one) pamu2fcfg -n >> ~/.config/u2f/keys # >>> Press button on second U2F token # >>> Remove token # ... Repeat for each additional token # Edit PAM configuration files sudo $EDITOR /etc/pam.d/screensaver ### Add a line with: # auth required <path to pam_u2f.so> authfile=<path to mapping file> sudo $EDITOR /etc/pam.d/authorization ### Add a line with: # auth required <path to pam_u2f.so> authfile=<path to mapping file>