The Gap Between the Key and the Browser

▶ Listen to this article

I had what felt like a simple question: in 2026, can I sign a document in a browser using a hardware token? Not authenticate. Not log in. Sign — produce a cryptographic signature, using a private key that lives on a YubiKey or a smartcard, that some other party can later verify.

The answer turned out to be more interesting than I expected. The headline version is no, you can’t — not from a normal web page, not without installing native software. The interesting part is why. Every browser API that gets close to this stops just short of it, and the stopping points form a pattern. The pattern is deliberate.

Three APIs, three fences

Modern browsers expose three cryptographic surfaces that you might reach for:

WebAuthn is what you’d think of first. Tap your YubiKey, get a signature, ship it to a server. Except WebAuthn was designed for authentication, and the signature it produces doesn’t sign your document. It signs a fixed-format blob: authenticatorData ‖ SHA-256(clientDataJSON)1. Your document hash can ride inside clientDataJSON as the challenge, but the authenticator wraps it in framing bytes you can’t strip out. The result is a WebAuthn-flavored signature, not a CMS or PAdES signature. PDF readers won’t accept it. eIDAS validators won’t accept it. The signature is real cryptography — it just isn’t the artifact you needed.

Yubico is actively prototyping a sign extension to WebAuthn that would let you sign arbitrary data2, currently sitting at Version 4 of an editor’s draft. WebAuthn Level 3 reached Candidate Recommendation in January 20263, and the raw signing extension is explicitly not in it. It will land later, somewhere, in something. Not today.

WebCrypto (window.crypto.subtle) can absolutely sign data. RSA-PSS, ECDSA, even Ed25519 now4. The key can be hardware-backed by the platform — Windows TPM, macOS Secure Enclave — if the browser and OS cooperate. But that’s a platform key, generated on this machine, bound to this machine, with no portable existence. It is not the key on your YubiKey. Pulling your token out and walking to a different laptop with it changes nothing for WebCrypto. The hardware that holds the key has to be the hardware the browser is running on.

WebHID lets web pages talk to HID devices: game controllers, custom keyboards, exotic peripherals. Your YubiKey exposes an HID interface, so this seems promising — until you read the security questionnaire on the WebHID spec5. FIDO and security-key HID interfaces are explicitly excluded from the WebHID device chooser, by design. The browser intentionally refuses to let you select your YubiKey as a WebHID device. The reason is that letting a web page talk directly to a FIDO authenticator over HID would let malicious sites impersonate the browser’s own WebAuthn flow.

Also: even if WebHID let you select your YubiKey, the PIV applet doesn’t use HID. It uses CCID — the standard smartcard interface — which the browser exposes through nothing. Two different fences, both real, both at the same line.

Three APIs. Three different stopping points. None of them gives a normal web page direct cryptographic operations on a portable hardware key.

The surprise: Chrome shipped the missing piece

While I was researching this, I expected to find the same “no, the browser fence is solid” story I started with. Instead I found that Google shipped a new API in October 2025 that actually crosses the line: the Web Smart Card API, in Chrome 1436. It exposes navigator.smartCard, which connects to the OS PC/SC subsystem and lets you do real APDU communication with a smartcard. Real signing operations on a real hardware key. From the browser.

With one catch: it only works in Isolated Web Apps7. Not normal web pages. Not extensions. A separate class of installable web application with stronger origin and policy guarantees, gated behind enterprise device policy on ChromeOS for now, planned to expand to other platforms as IWAs themselves expand.

The Blink API owners were explicit about why. Reilly Grant’s approval message says it directly: “This API exists to support specific, mainly enterprise-focused, use cases. On the broader web, device-based authentication solutions such as WebAuthn are more appropriate.”8 Chrome built the path to PIV. It then put a wall around the path saying normal websites don’t get this. The wall is the point.

Firefox and Safari haven’t signaled implementation interest. Chrome’s path is real but narrow, and it’s not what a normal web page can reach.

The EU’s answer: don’t put the key in the browser at all

The big regulatory forcing function I expected to bend the browser story is eIDAS 2.09. Regulation (EU) 2024/1183 came into force in May 2024 and requires every EU member state to ship a European Digital Identity Wallet by December 24, 2026. The wallet must support Qualified Electronic Signatures — the legally-binding tier — free of charge for natural persons. Hundreds of millions of EU citizens, signing documents with state-issued cryptographic identity, by the end of this year.

I assumed this would push browser vendors to expose hardware token signing. It hasn’t. The EUDIW is a smartphone app, not a browser feature, and browser integration happens through the wallet via the OpenID4VP protocol or through cloud-based signing using the Cloud Signature Consortium API10. The keys live in the wallet on the phone, or in the Qualified Trust Service Provider’s cloud HSM. They don’t live in the browser; they don’t live on a USB token in your laptop’s USB port; they don’t get touched by JavaScript.

The EU looked at the same problem and answered: put the key somewhere with a known trust model — a certified mobile wallet or a regulated cloud HSM — and have the browser talk to that, not to local hardware. The hardware token in the browser path was politely declined.

Estonia already solved this, with the obvious caveat

The exception is the country that has been running mass browser-based qualified signing for over a decade. Estonia’s Web eID project11 is the most mature deployed solution for browser-native document signing with physical ID cards, and it works across Chrome, Firefox, Edge, and Safari on Windows, macOS, and Linux. It supports the ID cards of Estonia, Latvia, Lithuania, Finland, Belgium, and Croatia. It’s open source. It’s used by millions of people for legally-binding signatures.

It’s also a browser extension plus a native companion app. The web page invokes the extension via JavaScript; the extension talks to the native app via native messaging; the native app drives PC/SC and PKCS#11 to reach the card. The browser refused to expose the hardware. Estonia built an extension shaped exactly like the gap, with a binary on the other end of the gap.

This is the third path: don’t break the browser fence, build a bridge across it that the user installs deliberately. It works. It also means a vendor or a government has to ship native software per platform, and the user has to trust the native binary as much as they trust their browser. The fence stayed up. A door was added.

Why the fence is principled

A pattern shows up in every one of these stopping points. WebAuthn deliberately requires authenticator consent (the physical touch) for every cryptographic operation, and limits what the signature covers, because anything more permissive turns the authenticator into a remote signing oracle for whichever site you happen to be visiting. WebHID’s FIDO exclusion exists because direct HID access to a security key lets a hostile origin impersonate the browser’s own auth ceremony. WebCrypto’s hardware-backed keys are bound to the platform because portability would make them indistinguishable from cookies you can’t delete. The Web Smart Card API is IWA-only because direct PC/SC from arbitrary web origins is a footgun the size of an enterprise breach.

The browser’s job is to be the thing that mediates trust between origins. A hardware token is a powerful piece of capability — it can sign things that bind you legally. Giving any web page on the open internet the ability to invoke that capability, even with a user prompt, is a permission model the browser has consistently and correctly refused to ship.

The Estonian model gets this right. The native companion is something you installed deliberately, once, with a known provenance. It binds the powerful operation to a specific software boundary you can see. The browser delegates to it but doesn’t become it.

Where this is heading

Three things are dismantling the fence from different directions simultaneously, none of them fully:

  1. WebAuthn raw signing extension will eventually land in browsers and let WebAuthn produce CMS-compatible signatures over arbitrary data. This makes “tap to sign” a primitive of the web platform — but only for keys already enrolled as WebAuthn credentials, not arbitrary PIV slots on an existing card.
  2. Web Smart Card API is real and shipping, and will probably expand beyond IWAs as the IWA model matures. Enterprises with managed Chrome installs get this first. Open-internet web pages probably never do.
  3. eIDAS 2.0 and EUDIW will make qualified signing routine for hundreds of millions of users — by putting the key in a phone, not in the browser. The “hardware token in the browser” question gets quietly bypassed.

None of these gives a normal public website on the open internet direct access to a YubiKey’s PIV key for document signing. That gap, specifically, is the one the platform has been consistent about not closing.

I think it’s the right call. The signing capability is too powerful to be reachable from any tab. The browser’s fence was always more principled than I assumed it was — every layer stops at exactly the same place, for related but distinct reasons, with a coherent design philosophy about what trust the browser is willing to broker. The interesting evolution isn’t browsers giving in. It’s the ecosystem building deliberate, scoped, installable paths across the gap, while leaving the gap itself in place.

Sometimes the most thoughtful thing a platform does is refuse to give you what you asked for.

— Pete


  1. Yubico, “Using WebAuthn for Signing”, Yubico Developer documentation. Explains the structure of what WebAuthn actually signs and the challenge-as-document-hash workaround pattern, including its limitations for producing standard signature formats. 

  2. Emil Lundberg (Yubico), “WebAuthn Sign Extension”, Editor’s Draft Version 4, August 26, 2025. Independent draft specification for extending WebAuthn to sign arbitrary data. Intended to be upstreamed to the W3C WebAuthn spec after prototyping. 

  3. W3C, “W3C Invites Implementations of Web Authentication: An API for accessing Public Key Credentials Level 3”, W3C News, January 13, 2026. Candidate Recommendation announcement. The raw signing extension is not part of Level 3. 

  4. W3C, “Web Cryptography API”, W3C specification. Ed25519 (EdDSA) support was added in 2024 after a spec bug fix and now ships in all major browsers. RSA-PSS, RSASSA-PKCS1-v1_5, and ECDSA have shipped for years. 

  5. WICG, “WebHID Security and Privacy Questionnaire”, Web Incubator Community Group. Documents the explicit exclusion of FIDO authenticator HID interfaces from the WebHID device chooser as a deliberate security design decision. 

  6. Luke Klimek (Google), “Intent to Ship: Web Smart Card API”, blink-dev mailing list, October 2, 2025. Chrome 143 shipping milestone, approved by Blink API owners (Reilly Grant, Alex Russell, Mike Taylor, Daniel Clark). 

  7. WICG, “Web Smart Card API”, Unofficial Proposal Draft, updated May 26, 2026. Spec text including the Isolated Web App requirement and the architecture mapping navigator.smartCard operations to PC/SC SCardConnect / SCardTransmit

  8. Reilly Grant, LGTM message on Intent to Ship thread, blink-dev, October 2025. “This API exists to support specific, mainly enterprise-focused, use cases. On the broader web, device-based authentication solutions such as WebAuthn are more appropriate.” 

  9. European Commission, “European Digital Identity”, official EU information page. Regulation (EU) 2024/1183 entered into force May 20, 2024; member-state EUDIW deadline December 24, 2026; QES creation free of charge for natural persons (Article 5a). 

  10. Cloud Signature Consortium, “CSC API v2”, CSC standards. The API protocol used by browser apps to invoke remote QES signing through Qualified Trust Service Providers’ cloud HSMs — the dominant browser-facing QES path under eIDAS 2.0. 

  11. Web eID Project, web-eid.eu and web-eid GitHub organization. Browser extension plus native companion app architecture for legally-binding QES from Chrome, Firefox, Edge, and Safari on Windows, macOS, and Linux. Open source, EU-funded, supports 6 EU countries’ national ID cards.