Back to Devoured - May 12, 2026
DEVOURED
Laptops all have built-in security tokens these days

Laptops all have built-in security tokens these days

Tech Andrew Helwer
Andrew Helwer realized after five years that his collection of yubikeys is redundant because every modern laptop has a built-in secure element that works as a security token.
What: Helwer walks through configuring macOS Secure Enclave and Windows Hello to replace physical security tokens for SSH authentication and git commit signing. On macOS, this involves sc_auth create-ctk-identity, ssh-keygen -w /usr/lib/ssh-keychain.dylib, and configuring git to use ssh-agent instead of direct file paths. On Windows, ssh-keygen -t ecdsa-sk integrates with Windows Hello for facial recognition or fingerprint auth.
Why it matters: Physical security tokens like yubikeys have been the gold standard for protecting SSH keys and git signing, but they're now redundant hardware. Laptops since 2020 ship with hardware secure elements (Secure Enclave on Mac, TPM on Windows) that provide the same guarantee: private keys never leave the device, and operations require physical presence. The shift matters because it removes friction from security workflows without compromising protection.
Takeaway: If you currently use a yubikey for SSH or git signing on a Mac, you can switch to the built-in Secure Enclave using the commands at https://ahelwer.ca/post/2026-05-08-builtin-u2f/. Windows users can run ssh-keygen -t ecdsa-sk to generate keys backed by Windows Hello.
Deep dive
  • Security tokens like yubikeys store private/public keypairs where the private key can never be extracted, only used in-place for signing operations gated by physical interaction (button press or fingerprint)
  • Modern laptops have equivalent hardware: Apple's Secure Enclave and Windows TPM provide the same private key isolation and physical presence requirements
  • For SSH: ssh-keygen -t ed25519-sk (with physical token) or sc_auth create-ctk-identity + ssh-keygen -w /usr/lib/ssh-keychain.dylib (macOS Secure Enclave) generates keys that require physical presence
  • The private key file is just a handle to the actual key stored in hardware, so it can be safely shared publicly
  • For git commit signing via SSH: configure git to use ssh-agent instead of direct file paths, set user.signingKey to key::${public_key_contents}, enable with git config --global commit.gpgsign true
  • Drawback of security tokens: users can become conditioned to approve requests without scrutiny, and lost tokens mean lost keys (no backup possible except BIP 39 word lists which compromise security)
  • SSH authentication and git signing are the primary use cases, but tokens also work for U2F web authentication, passwordless login, and sudo elevation via PAM on Linux
  • The fingerprint-reader yubikey has too high a failure rate for operations requiring many sequential approvals (like rebasing dozens of commits)
  • Windows implementation: winget install Microsoft.OpenSSH.preview, then ssh-keygen -t ecdsa-sk integrates with Windows Hello facial recognition, fingerprint, or PIN
  • Main benefit beyond security: your SSH access and git signing capability travels with your laptop instead of being tied to files on a specific machine or a fragile USB device sticking out of a port
Decoder
  • Security token / U2F: Hardware device (like yubikey) that stores a private/public keypair where the private key can never be extracted, only used in-place for signing operations. Physical interaction (button press, fingerprint) is required to authorize each signing operation.
  • Secure element: Hardware component in modern laptops (Apple's Secure Enclave, Windows TPM) that provides the same private key isolation and physical presence requirements as a physical security token.
  • SSH key signing: Using a cryptographic keypair to authenticate SSH connections instead of passwords. The private key proves your identity to the server.
  • Git commit signing: Cryptographically signing git commits with your private key to prove authorship and prevent commit forgery. Different from SSH authentication for push/pull.
  • BIP 39: Bitcoin Improvement Proposal that converts private keys into human-readable word lists (usually 12 or 24 words) for backup and recovery. Writing down the words allows private key restoration but defeats the security model of hardware tokens.
Original article

I've been a fan of security tokens for a decade now and have accrued quite a collection. This redundancy isn't a bad thing, as security tokens are easily misplaced and the only way to recover from a lost token is using a second token that is also registered with the service you're trying to access. I use security tokens whenever I can! SSH authentication, universal two-factor (U2F) authentication, passwordless local login, sudo command elevation, and git commit signing are all things I use security tokens for every day. When I take my laptop traveling, there also travels a yubikey. However, it took me an oddly long time to realize that I'm a relic of a bygone era. Laptops and smartphones all have built-in security tokens these days! I've been carrying around yubikeys when an even better one is built right into my macbook. This post is about how I use security tokens, and how I configured my laptop's secure element to replace my yubikey collection.

The security token promise

Security tokens like yubikeys (or SoloKeys and Nitrokeys if you want FOSS firmware) have a private/public keypair baked into them. Their promise is that while the public key is easily retrieved, the private key can never leave the device. The only thing you can do is send packets of data to the device to be signed in-place by the private key, and this operation is gated behind some physical user interaction like pressing a touch-sensitive button when it flashes. Fancier security tokens add a biometric flourish with a built-in fingerprint reader, but the real value is stopping attackers from making progress with purely remote access. If an attacker remotely accesses your computer, they still can't get your security token to sign random things without you doing something in the real world! Much better than your full SSH private/public keypair sitting in some files in the ~/.ssh directory.

There are drawbacks to this. Users can become conditioned to press the security token whenever it flashes, which could easily be a malicious request. If you're in the middle of repeatedly pressing the security token for a series of signing operations, do you really notice when it flashes an extra time? So companies like Apple and Microsoft have their own authenticator apps running on your smartphone that attach every access request to a random numeric code that has to be typed in. However, this is a fairly tedious and removes a lot of the usability benefit of security tokens vs. time-based one-time passwords (TOTP) as implemented by the authy or google authenticator apps.

Another drawback of security tokens is that if you lose one, its private key is gone for good. There's no way to back it up! So when you buy a security token, you really commit to buying at least two security tokens unless you want to risk locking yourself out of your various accounts. There is one alternative: maybe the only thing the cryptocurrency industry has contributed to the wider world is a moderately user-friendly method of backing up & restoring private keys by converting them into human-readable word list (see BIP 39) that can be written down. Of course this has produced some very innovative phishing attacks to convince users to write down that list of words in the wrong place, but that's the game you play if you allow private keys to leave a secure enclave. Still, if you're really paranoid about losing all of your security tokens you can use BIP 39 word lists as a method of last resort for regaining access to your systems.

How I use security tokens

I started off using my security tokens for SSH. If you just run ssh-keygen, it'll output a pair of files - one of which includes your full private key! But it's possible to have your private key live on a security token. I accomplished this by following the FIDO/U2F instructions here, which boil down to installing libfido2 then running ssh-keygen -t ed25519-sk while your security token is plugged in. This again generates a pair of files, but this time the "private key" file is only a handle to the private key that actually lives on the security token. Thus I feel confident pasting that private key file here for all to see!

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACD9zOiJ55uYy6qviTz+RiSspJpLrau+pN3o6MZX
A+eFKwAAAARzc2g6AAAA+EZ0QmdGdEJnAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
9tAAAAIP3M6Innm5jLqq+JPP5GJKykmkutq76k3ejoxlcD54UrAAAABHNzaDoBAAAAgBNm
0IZwRiRE+zjuIvj6JjAUW1gYHiewTNA90UV2igEeJ80p7OdCumpNXaok232zclR2gDZaK3
AZOU8OOKeD3bklnL9WmyoeZi58wdKb9C4lSfH+7Hs5thbu5Jgg6i6Aha3qjPtXCSGJiH/i
RCI4Th7n72GEaSrW0leTAHk1MyDZAAAAAAAAABZhaGVsd2VyQGFoLW1iYWlyLmxvY2FsAQ
ID
-----END OPENSSH PRIVATE KEY-----

Running ssh-keygen -t ed25519-sk again with the same security token should generate the same private/public key files on any computer you have it plugged in to, so your SSH access capabilities travel with the security token instead being tied to a specific file on a specific computer.

Probably 90% of the time I press my security token it's for git. Every git forge I know of implements SSH authentication for push & pull operations, and you can upload the id_ed25519_sk.pub file generated above so it accepts your security token keypair. Git also supports SSH keys for commit signing; you can read how to set this up here and then run git config --global commit.gpgsign true to automatically sign every commit. You'll also need to upload your public key again so your git forge recognizes your commits as being signed by you (this is usually a separate field from the SSH authentication one).

Note that using security tokens to sign commits can be a bit annoying. While rebasing a long series of commits, you'll have to re-sign every single one! This is what made me stop using the fingerprint reader yubikey, because the fingerprint read failure rate was just way too high to successfully sign dozens of commits in a row. Maybe there's a way to configure this behavior, since in jujutsu (which is basically a "rebasey/amendy" wrapper of git) there is a way to only sign commits on push.

Finally, I use my security tokens for passwordless local login & sudo elevation on Linux systems, as a Pluggable Authentication Module (PAM).

Just using my laptop

Having a security token constantly hanging out of my laptop's USB-C port is a bit precarious. It sits out there like a little lever waiting to destroy the port (and itself) if dropped or bumped the wrong way. However, when things generally just work you tend not to think about how to replace them, so it took me an entire half-decade to consider that maybe I don't need that security token at all! My laptop has one built in! Can I just use it instead?

I tried following Arian van Putten's excellent instructions on my 2020 m1 macbook air:

sc_auth create-ctk-identity -l ssh -k p-256-ne -t bio
ssh-keygen -w /usr/lib/ssh-keychain.dylib -K -N ""

This created id_ecdsa_sk_rk private/public keypair files which I moved into my ~/.ssh directory. Again I can safely paste the private key file here for all to see:

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQRsRRHZyIOq
ac/qUAnXdXorIzleIMa4zL9WOEm7XS6EpugiQoD2equ5ZzcrkELHZ0uP05ZbHOuegEC+wT
tzkuO3AAAABHNzaDoAAACw4XQCeeF0AnkAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEbEUR2ciDqmnP6lAJ13V6KyM5XiDGuMy/Vj
hJu10uhKboIkKA9nqruWc3K5BCx2dLj9OWWxzrnoBAvsE7c5LjtwAAAARzc2g6IQAAABTp
WyIrRBYp86ZnfGCWxVVSwAvHJwAAAAAAAAAEc3NoOgECAwQ=
-----END OPENSSH PRIVATE KEY-----

After running ssh-copy-id -i ~/.ssh/id_ecdsa_sk_rk.pub <server nickname> to add the public key as an authorized key on one of my homelab boxes, I added the following into my ~/.ssh/config file:

Host *
  IdentityFile ~/.ssh/id_ecdsa_sk_rk
  SecurityKeyProvider=/usr/lib/ssh-keychain.dylib

I was then able to run ssh <server nickname> and be automatically prompted with a thumbprint request from macOS before logging in smoothly! Amazing!

But can I use it for git? After setting git config --global user.signingKey /Users/ahelwer/.ssh/id_ecdsa_sk_rk and updating the .ssh/allowed_signers file, unfortunately it doesn't work - git can't sign the commit, and produces an error like:

error: Signing file /var/folders/l5/5wqvq2l10p96wtdtfr6lvrvw0000gn/T//.git_signing_buffer_tmpc4uQgO
Confirm user presence for key ECDSA-SK SHA256:oQDA2SNYb2MoSQcxJVSmWyAeAWPqMp7rxliBRfi87as
Couldn't sign message: device not found?
Signing /var/folders/l5/5wqvq2l10p96wtdtfr6lvrvw0000gn/T//.git_signing_buffer_tmpc4uQgO failed: device not found?

fatal: failed to write commit object

The fix is to use ssh-agent instead of pointing directly to files in the ~/.ssh directory. Following instructions from the ever-helpful tutorial from above, we run this command to make the keypair known to ssh-agent:

ssh-add -K -S /usr/lib/ssh-keychain.dylib

Then, instead of pointing to a filepath for user.signingKey, point directly to a key in your ~/.gitconfig as in:

[user]
	name = Andrew Helwer
	signingKey = "key::sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGxFEdnIg6ppz+pQCdd1eisjOV4gxrjMv1Y4SbtdLoSm6CJCgPZ6q7lnNyuQQsdnS4/Tllsc656AQL7BO3OS47cAAAAEc3NoOg== ssh:"

which is the contents of ~/.ssh/id_ecdsa_sk_rk.pub prefixed with key::. After that, I am pleased to proclaim that this very file you are reading was signed & pushed to my gitlab pages site using the key from my macbook's secure element!

I also ran a quick experiment on my corp-issued Windows laptop:

winget install Microsoft.OpenSSH.preview
ssh-keygen -t ecdsa-sk

This again generated a pair of private/public key files, and anytime I SSH'd somewhere it went through the standard Windows Hello login flow accepting facial recognition, fingerprint, or my PIN.

I unfortunately do not have access to a Linux laptop with a secure element gated behind a similar real-world user presence check, so can't demonstrate anything there. If you're able to try it out, please let me know!

Explore all 40 articles in today's digest

Fresh dev news, AI-digested daily. Never miss a trend at devoured.fyi