Automating a YubiKey for Agentic Logins

Agentic Logins

Agents! Coding agents, enterprise agents, personal assistant agents, computer use models, etc. You know the drill. We’ve gone quickly from tech demos to doing real work. Agents are all over the place being productive and helpful on your behalf (and hopefully not hacking into companies).

Sometimes, these agents need to go to websites to do things. Sometimes, these agents need to log in on your behalf to said websites. And sometimes, said websites make it really painful for agents to log in. This can be intentional (CAPTCHAs, anti-bot, etc) or unintentional (inscrutable authentication processes). The former is a whole can of worms around how we should design the future of the web for agents vs humans. Thankfully we are not going to open that can today. Instead, we’re going to talk about the latter: the pains of dealing with agentic login and one fun workaround I (unfortunately) had to develop.

I run a somewhat-sophisticated personal app that logs into a bunch of different web portals. These portals are not the shining example of modern machine/agent-ready websites. They don’t have APIs, MCP, or any interfaces that would make life a lot easier. So, interactive login and scraping is currently the best available approach. I have headless browser automation that uses a shared human-user credential for login. Typically this is username/password + some form of 2FA, depending on the web portal. That form of 2FA can range from TOTP, an SMS OTP, a phone call, an email code/magic link, a mobile app push approval, a security key, a passkey, etc.

Having started Duo, this diversity of 2FA methods is unsurprising. All of these 2FA methods were designed for human-interactive login, not automated/agentic use. It’s easy enough to give your agent a username/password to log in, but automating the 2FA step can range from a little more painful to a lot more painful. Note: Giving replayable credentials to a non-deterministic agent can be a dangerous proposition, but my automations are a bit more deterministic than pure computer use models.

So, let’s walk through each common form of 2FA and what we can do to automate logins:

Method What it assumes Agent difficulty How an agent does it
TOTP (authenticator app) A shared secret on your phone Easy Store the TOTP seed and compute the OTP on-demand.
Passkeys / WebAuthn A platform or password-manager authenticator Easy Store the key material and compute signatures on-demand. Some sites may require hardware attestation or user verification.
Email OTP An inbox you read Medium Route email to an address/inbox that the agent can read, parse the code out, and race delivery delays.
SMS OTP A phone with a SIM Hack Rent a virtual number (via Twilio) and receive the text via a webhook. Lots of dragons here with VoIP blocking, shortcode delivery, etc.
Voice call OTP A person who answers and listens Bigger hack Again a virtual number, with speech-to-text transcription to extract the OTP out. An alternative model may require you to enter an OTP via DTMF.
Push approval The vendor’s app on your phone Biggest hack You’d have to emulate the vendor’s mobile app. Not worth the squeeze.
Hardware security key (U2F/FIDO2) A physical hardware key and user-presence touch Hard, but we’re going to do it The key never gives up its secret, and every signature needs a physical touch. Or does it…

There are clearly pros/cons in terms of automating the different 2FA methods above. Note that this is different than the pros/cons of the security and usability of the methods. Maybe surprisingly, there is not an inverse correlation between security and automation (e.g. passkeys are strong, usable, and easy to automate). Again, in an ideal world, we’d have APIs/MCP and real delegated credentials for agents that are scoped, revocable, auditable. But, we’ve got to live with the web that we have today, until we get to a better place.

Automating a YubiKey Touch

Most of the portals that my app logs into support TOTP, SMS, or email codes. These are pretty reasonable to support. Clearly TOTP is the ideal setup. Email is ok, especially if you can set up a different user with a dedicated programmatic “inbox” (e.g. Resend). And SMS is decent with Twilio although there are some limitations with shortcode senders.

There is one critical web portal the app uses that only supports phone call OR a hardware security key (specifically, an attested Yubico YubiKey). The telephony-based phone call method works, but it can be a little flaky. Deliverability, audio quality, timing issues, transcription mistakes, etc. All the things you would expect from a POTS/PSTN call even if it’s happening via VoIP. So, I had the idea of trying to automate a YubiKey challenge/response. It’s not strictly necessary, but improves the reliability and security of the login process AND seemed like a fun challenge to take on.

The Plumbing

In a normal YubiKey login process, a website sends a challenge to the browser which interfaces with the YubiKey over USB via CTAP2. The user may type a PIN and touch the capacitive sensor of their YubiKey to confirm user presence.

Diagram of a normal security-key login: the website sends a challenge to the browser over HTTPS, the browser sends a hash of the challenge and origin to the security key over USB, you enter the PIN and touch the key, and the signature goes back through the browser to the website.

This doesn’t seem insurmountable to automate. We need some way to proxy the FIDO challenge from the browser and then some way to automate the physical touch/tap on the YubiKey capacitive sensor.

First, the plumbing/proxying part. This app runs on Vercel and the automations run from a disposable Vercel Sandbox. The automations are driven by Playwright with a headless Chromium browser. The YubiKey is hosted elsewhere (obviously not in the cloud), plugged into a USB port on a physical host that can communicate with the sandbox. When the app logs into the portal, the headless browser captures the FIDO challenge, relays it to this physical host, the challenge is transmitted to the YubiKey, the YubiKey “touch” happens, the signature response is generated, and the response is shuttled back to the sandbox and provided to the portal website. It looks something like this:

Diagram of the relayed login: a headless browser with a shim on a cloud machine forwards the website’s challenge over the internet to a relay on the machine with the key. The relay talks to the security key over USB and tells a robot finger to touch the key when it asks, and the signature flows back the same way.

Security note: This isn’t just a YubiKey signing oracle sitting wide-open on the internet. There are a variety of compensating controls ensuring that only the automation in the sandbox can request a signature and only for a specific set of origins/URLs.

The Touch

Ok, this is the main event. The real question is: How can we automate the actual human touch/tap on the YubiKey?

Each YubiKey, regardless of form factor, has a gold contact that is a capacitive touch sensor. Its goal is to ensure there is some human verification for a login/transaction. That touch logic, if requested, is contained within the key’s firmware itself, so the YubiKey will not allow its private key material to sign a challenge without the touch.

A YubiKey 5 NFC, with its round gold touch sensor

I’m not the first person to try to emulate a YubiKey touch. In 2022, Yossi Meloch at Cisco wrote about automating a YubiKey button press with a mechanical approach. A SwitchBot button pusher, triggered through its API, pressed a metal door pin key against the touch area, and a grounded headphone cable made the sensor read the metal as a finger. But I wanted something that was a little more production-grade and avoided any mechanical/moving parts.

My first experimentation was figuring out how I could manually trigger a “touch” without my finger acting as a capacitive ground. This turned out to be relatively straightforward. I taped a jumper wire to the YubiKey sensor with some conductive copper tape and was able to touch that wire to ground to trigger the YubiKey “touch” when prompted. Note that the capacitive sensor appears to go through some initialization/calibration when the key is first plugged in and powered up via USB, so you have to ensure your wiring is in its resting non-connected state.

Next was trying to introduce some switching in the process. Instead of the mechanical switch with moving parts, I wanted a simple relay switch that could be programmatically controlled to pull the sensor pad to ground to emulate the touch. This part took a fair bit of trial and error, mostly because I am far from an electrical engineer. I can debug software, but when weird things are happening in hardware-land, I’m at a bit of a loss. Thankfully, my father is an electrical engineer and I’ve got a good friend Claude who can help me along the way. After cycling through a few different switches, including a PC817 optocoupler that never quite worked (WTF is a picofarad and why is it throwing off my experiment?!), I found success in using a simple reed relay (SIP-1A05).

The last part was tying it all together with automation. The main brains of my setup is a Raspberry Pi Pico device. This is a USB microcontroller that can be easily programmed via MicroPython to receive touch requests via the on-host relay and then drive the Pico logic to “touch” our sensor. When the on-host relay sends the FIDO challenge to the YubiKey, the YubiKey will start sending CTAP keepalives with status UPNEEDED, indicating it is waiting for a touch. The relay program watches for that status and then sends a TOUCH 300 command over USB serial to the Pico, telling the running MicroPython program to “touch” the key for 300 ms. That “touch” event drives one of the Pico GPIO pins high to 3.3v, which is sufficient to power the reed relay coil (despite being rated for 5v) and close the contact, bridging the YubiKey sensor to ground and successfully triggering a “touch”.

Wiring diagram: the Pico’s GP15 pin drives the coil of a SIP-1A05 reed relay, with a 1N4148 flyback diode across the coil. The relay’s contacts connect foil on the YubiKey’s touch pad to common ground.

The experimental breadboard version (with the non-functioning PC817) was a bit messy:

Breadboard prototype: a Raspberry Pi Pico with jumper wires running to a YubiKey with copper tape on its touch sensor

But the production soldered version cleaned up nicely:

Soldered version: the Pico and reed relay on a blue protoboard, wired to the YubiKey’s touch sensor

And, it worked! End-to-end, from the browser automation running in the Vercel Sandbox, to the relay running on the physical host, to the Pico driving the automated “touch”, and back again.

Is this a good idea? For my use case, yes. It is faster, more reliable, and more secure than the telephony-based login process that I was previously using. For the internet? Maybe. We have to be aware that future agentic access on the web may look very different than the last couple decades, and we’ll have to do a bunch of new work around agentic authentication and authorization. In the meantime, we’ll undoubtedly have to cobble together some hacks to make things work as desired.

Building Your Own

Software

All the required software for (1) the Playwright browser shim in the Vercel Sandbox, (2) the relay running on the physical host, and (3) the firmware running on the Pico were all written by Claude Code. If you’re interested in checking out the code, just ping me and I’ll clean it up and post it on GitHub. Given that this is very tailored to my specific application and use case, it would probably be easier just to ask Claude to build it for you!

Hardware

Here’s a quick parts list, if you want to duplicate my exact setup described above.

Part Where to buy Notes
YubiKey 5 NFC (USB-A) Amazon, Yubico Dedicated hardware key for the agent.
Raspberry Pi Pico H (RP2040) Amazon, DigiKey Runs MicroPython. Needs a micro-USB cable.
SIP-1A05 reed relay Amazon, DigiKey The one relay that worked. Or SIP-1A05D if you want a built-in diode.
1N4148 diode Amazon, DigiKey Flyback protection across the coil.
Conductive copper tape Amazon A small square on the key’s touch sensor.
Solid tinned copper wire Amazon Whatever wire you want.
Solderable breadboard Amazon, Adafruit For a more finished/soldered version.

© 2026 Jon Oberheide