YubiKeys are hardware security keys that you can adopt to be the second factor for authenticating to a wide variety of services. They can also securely store keys such that they can’t1 be recovered from the device which means they can’t be stolen by bad actors.

There are a number of guides out there for doing this many of which are much better written than this blog post2. However they generally tend towards a much more extreme level of setup than I want or need to start with. They tell you how you must only generate keys on ephemeral virtual machines on isolated hardware connected to hardware random number generators stored in a maze of twisty passages all alike guarded by two guards one of whom always lies and the other of whom always tells the truth. You have been eaten by a Grue.

This can be justified if you’re protecting high value assets or have enemies with vast technical resources and a burning hatred of your existence. I’m trying to protect access to the source code of this blog and my enemies are rather more pedestrian. That means I can afford to be rather more relaxed in my key generation.

If you are not me consider reading the articles in References from which I have derived this to see if they better match your needs.

Getting started

Let’s install some software3. We need GnuPG to talk to the YubiKey. DO NOT QUESTION WHY4. We also need something to prompt for PINs because SECURITY. We are going to download these things from The Internets and assume everything is ok.

brew install gnupg pinentry-mac

I now need a key. We could create a key locally and import it onto the YubiKey and then rigorously prove the key have been safely deleted. Or we could use the YubiKey to generate the key. As keys cannot be exported this means if the YubiKey is lost or damaged the key is lost. However my recovery strategy for this is disassociate the key from GitHub and create a new one. So having a backup is low value. Creating the key on the YubiKey is easier so let’s do that.

gpg --card-edit

This allows us to use the inbuilt apps on the YubiKey to configure it. I recommend starting with changing the default PINs.


Change the values of both the user and admin PINs to something more random. The defaults are 123456 and 123456785 and the new ones must be at least 6 and 8 digits long respectively.

Then set the key length. I am using RSA 4096 bit everywhere.


Once that’s done generate a key. I didn’t do an off-card backup because my use case doesn’t require it.


Once you have the key generated quit the card editor.

Shell integration

To get fish shell to integrate with GPG add the following to your ~/.config/fish/config.fish file.

set -x GPG_TTY (tty)
set -x SSH_AUTH_SOCK ~/.gnupg/S.gpg-agent.ssh

Now open a new fish shell (or run the above in your current shell) and run:

gpgconf --launch gpg-agent
ssh-add -l

This should list a key. If it does not list a key then you have failed6. If it works kill the agent without mercy.

killall gpg-agent

Configure GnuPG

Edit ~/.gnupg/gpg-agent.conf to add:

pinentry-program /usr/local/bin/pinentry-mac

To enable the key for SSH usage run:

gpg -K --with-keygrip

Get the Keygrip value and add it to ~/.gnupg/sshcontrol

In order to get gpg-agent to run automatically you can use launchd. This blog post describes the process you can use to do so.

Configure GitHub

Export your public key and copy it to your clipboard with this handy command.

ssh-add -L | grep -iF 'cardno' | pbcopy

Add this as an SSH key to your GitHub account.

Assuming everything is working you should now be able to run:

ssh git@github.com

This should pop up a window to prompt you for a PIN. Enter the user PIN you set on your YubiKey earlier. SSH should tell you that you’ve successfully authenticated7 but that GitHub does not provide shell access8.


  1. Possibly the NSA can recover them. If your threat model includes the NSA I cannot help you. I refer you to James Micken’s helpful Mossad/not-Mossad duality. ↩︎

  2. This is admittedly a low bar. ↩︎

  3. If you have angered a nation state you will wish to validate this somehow. I leave this as an exercise for the reader. ↩︎

  4. We need something that can and this is that something. ↩︎

  5. Just like your luggage ↩︎

  6. Or these instructions are incomplete ↩︎

  7. Yay ↩︎

  8. The monsters ↩︎