Using a YubiKey 5C for SSH and Git Authentication on Linux

Feb 9, 2026

Your SSH private key sits on your disk, protected by (hopefully) a passphrase. But passphrase or not, it's still a file — and files can be stolen, copied, or exfiltrated by malware. A YubiKey changes the equation entirely: the private key lives on the hardware token and can never be extracted.

This guide walks through setting up a YubiKey 5C for SSH authentication and Git operations using the FIDO2 ed25519-sk key type, including commit signing and a practical dual-key setup for when your YubiKey isn't at hand.

Prerequisites

  • A YubiKey 5C (which supports FIDO2 and ed25519-sk)
  • OpenSSH
  • libfido2 installed on your system
# On Fedora:
sudo dnf install -y openssh libfido2

# On Debian/Ubuntu
sudo apt install -y openssh-client libfido2-1

Install libfido2

How It Works

Unlike traditional SSH keys where the private key is a file on disk, FIDO2-backed SSH keys work differently. When you generate an ed25519-sk key, the private key is created and stored inside the YubiKey. The file saved to your ~/.ssh/ directory is just a "key handle" — a reference that tells SSH to ask the YubiKey to perform the signing operation.

This means that even if someone copies your key handle file, it's useless without the physical YubiKey.

Step 1: Set a FIDO2 PIN

If you haven't already, set a PIN on your YubiKey's FIDO2 application. You can do this with the YubiKey Manager:

# On Fedora
sudo dnf install -y yubikey-manager

# Other distros
# check https://www.yubico.com/support/download/yubikey-manager/

# Let's create the PIN if you haven't already
ykman fido access change-pin

Set the PIN

This PIN will be required when generating keys and (if configured) when authenticating.

Step 2: Generate a FIDO2-backed SSH Key

Plug in your YubiKey and run:

ssh-keygen -t ed25519-sk \
  -O resident \
  -O verify-required \
  -O application=ssh:work \
  -C "yubikey-5c" \
  -f ~/.ssh/id_ed25519_sk

generate the FIDO2 private key

Breaking down the flags:

  • -t ed25519-sk — generate an Ed25519 key backed by a security key
  • -O resident — store the key handle on the YubiKey itself, making it portable across machines
  • -O verify-required — require PIN verification on every use (not just physical touch)
  • -O application=ssh=<name> — the passkey name inside the Yubikey. The Yubikey 5C supports up to 100 different passkeys
  • -C "yubikey-5c" — a comment to identify this key
  • -f ~/.ssh/id_ed25519_sk — output file path

You'll be prompted for your FIDO2 PIN and asked to touch the YubiKey.

This creates two files:

  • ~/.ssh/id_ed25519_sk — the key handle (not the actual private key)
  • ~/.ssh/id_ed25519_sk.pub — the public key

Step 3: Add Your Public Key to GitHub / GitLab

Copy the public key:

cat ~/.ssh/id_ed25519_sk.pub

check your public key

Then add it to your Git host:

  • GitHub: Settings → SSH and GPG keys → New SSH key
  • GitLab: Preferences → SSH Keys

In this post, I'll consider that you will test it using GitHub but the same would apply to any other SSH connection.

Test the connection:

SSH_AUTH_SOCK="" ssh -vvv -i ~/.ssh/id_ed25519_sk -o IdentitiesOnly=yes -T git@github.com 2>&1 | grep -i "offering\|authenticated"

# Insider your PIN
# Touch the Yubikey to confirm
# and now you may see something like:
>> debug1: Offering public key: /home/user/.ssh/id_ed25519_sk ED25519-SK SHA256:xj/123456789qwertyuiosdfghjklxcvbnm explicit authenticator
>> Enter PIN for ED25519-SK key /home/user/.ssh/id_ed25519_sk: 
>> Authenticated to github.com ([1.2.3.4]:22) using "publickey".
>> Hi thenets! You've successfully authenticated, but GitHub does not provide shell access.

test auth

Your YubiKey should prompt for a PIN and a touch. You should see a welcome message confirming authentication.

Step 4: Configure Gnome Keyring (maybe optional)

Note: I don't know what is needed for KDE. Maybe you will need a similar fix for it.

Check if you need this fix:

# Try to authenticate without any extra param
ssh -T git@github.com

# PROBLEM if you get the following, you need to continue with the step 4
sign_and_send_pubkey: signing failed for ED25519-SK "/home/user/.ssh/id_ed25519_sk" from agent: agent refused operation
git@github.com: Permission denied (publickey).

check if you need to fix the desktop env keyring

The problem is that GNOME Keyring's agent doesn't understand FIDO2/ed25519-sk keys at all. It intercepts the request, doesn't know what to do with it, and refuses the operation.

echo $XDG_CURRENT_DESKTOP

# this must return `gnome`

make sure you are running Gnome

mkdir -p ~/.config/autostart
cp /etc/xdg/autostart/gnome-keyring-ssh.desktop ~/.config/autostart/
echo "Hidden=true" >> ~/.config/autostart/gnome-keyring-ssh.desktop

disable Gnome SSH keyring agent

Now, check if it worked. Log out of your desktop session and log back in (not just close the terminal — a full logout/login). After that, verify:

ssh -i ~/.ssh/id_ed25519_sk -T git@github.com

# If it worked, you will need to
# Add your PIN
# Touch the Yubikey to confirm your presence

test without the -o IdentitiesOnly=yes param

Step 5: Sign Your Git Commits

Git supports signing commits with SSH keys. Combined with a FIDO2-backed key, this gives you hardware-bound proof of authorship for every commit.

git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519_sk.pub
git config --global commit.gpgsign true

To also sign tags by default:

git config --global tag.gpgsign true

Upload the same public key to GitHub under SSH and GPG keys, but this time select Signing Key as the key type. Commits signed with this key will show as "Verified" on GitHub.

For local verification, set up an allowed signers file:

echo "$(git config --get user.email) $(cat ~/.ssh/id_ed25519_sk.pub)" >> ~/.config/git/allowed_signers
git config --global gpg.ssh.allowedSignersFile ~/.config/git/allowed_signers

Now you can verify commits locally with git log --show-signature.

Dual-Key Setup: YubiKey + Traditional Key Fallback

A practical concern: what happens when your YubiKey is at the office but you're on the couch with your laptop? The solution is to register two SSH keys with your Git host.

Generate a traditional key as a fallback:

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "laptop-fallback"
# set a strong passphrase when prompted

Add this second public key to GitHub as well, then configure ~/.ssh/config to try both:

Host github.com
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_sk
    IdentityFile ~/.ssh/id_ed25519

~/.ssh/config

SSH tries keys top-down. If the YubiKey is plugged in, the FIDO2 key is used (PIN + touch). If it's not present, SSH falls through to the traditional key (passphrase).

To avoid retyping the passphrase for the fallback key, let ssh-agent cache it once per session:

ssh-add ~/.ssh/id_ed25519   # prompts for passphrase once

On GNOME or KDE desktops, the system keyring typically handles this automatically after your first login.

Scenario Key used Experience
YubiKey plugged in ed25519-sk PIN + touch per operation
YubiKey not available ed25519 Passphrase (once per session via agent)

Portable Keys: Using Your YubiKey on a New Machine

Because we generated the key with -O resident, the key handle is stored on the YubiKey itself. On a new machine, you can pull it down without any file transfer:

cd ~/.ssh
ssh-keygen -K

This downloads the resident key handles from the YubiKey. Rename the files if needed and you're ready to go — no copying files between machines.

Troubleshooting

"Key enrollment failed: requested feature not supported" Your YubiKey firmware is too old for ed25519-sk. Check with ykman info. If below 5.2.3, use ecdsa-sk instead:

ssh-keygen -t ecdsa-sk -O resident -f ~/.ssh/id_ecdsa_sk

SSH silently falls through to the wrong key Use ssh -vvv git@github.com to see which keys are being tried and why they fail.

"Permission denied" after adding key to GitHub Make sure the public key on GitHub matches exactly. Re-copy it from ~/.ssh/id_ed25519_sk.pub.

Security Considerations

  • Always register a backup YubiKey. If you lose your only key with no fallback, you lose access to every service tied to it.
  • Treat the FIDO2 PIN seriously. It's the knowledge factor that pairs with the physical possession factor.
  • Avoid no-touch-required. It defeats the purpose of the hardware key by removing the presence check.
  • Agent forwarding (ssh -A) is risky. It exposes your key's usability to remote hosts. Avoid it unless absolutely necessary.

References

  1. Yubico — Securing SSH with FIDO2 https://developers.yubico.com/SSH/Securing_SSH_with_FIDO2.html
  2. Yubico — Git Commit Signing with YubiKey and SSH/FIDO2 https://developers.yubico.com/SSH/Securing_git_with_SSH_and_FIDO2.html
  3. Yubico — Securing SSH with the YubiKey (overview) https://developers.yubico.com/SSH/
  4. Yubico Blog — GitHub Now Supports SSH Security Keys https://www.yubico.com/blog/github-now-supports-ssh-security-keys/
  5. Fedora Magazine — How to use a YubiKey with Fedora Linux https://fedoramagazine.org/how-to-use-a-yubikey-with-fedora-linux/
  6. Fedora Magazine — Use FIDO U2F security keys with Fedora Linux https://fedoramagazine.org/use-fido-u2f-security-keys-with-fedora-linux/
  7. nixCraft — How To Set Up SSH Keys With YubiKey as 2FA (U2F/FIDO2) https://www.cyberciti.biz/security/how-to-set-up-ssh-keys-with-yubikey-as-two-factor-authentication-u2f-fido2/

Luiz Costa

I am a senior software engineer at Red Hat / Ansible. I love automation tools, games, and coffee. I am also an active contributor to open-source projects.