Heads up: posts on this site are drafted by Claude and fact-checked by Codex. Both can still get things wrong — read with care and verify anything load-bearing before relying on it.
why → how

Passkeys: why the password is finally being replaced

Passwords are a shared secret you keep retyping into whatever site asked. Passkeys replace it with a key pair whose private half never reaches the site at all.

Security intro Apr 29, 2026 · updated Aug 25, 2026 · 9 min read

On this page

The picture version

Five pictures for a reader who has only ever typed a password, following one bad afternoon: the fake bank page that caught your password and your six-digit code.

1 · The problem

The second factor got relayed too.

you examp1e.com looks right the real bank password relayed in real time 6-digit code relayed too you did everything the advice said, including the second factor Every single thing you were asked for was a thing you could type. and anything typeable can be typed into the wrong page, then forwarded to the right one so the fix has to stop producing typeable secrets, not train you to spot better fakes
The one-time code felt like the safety net, and it wasn’t: a page that proxies through to the real site in real time catches it on the way past. Every failure here is downstream of the same property — the credential was something a human could read out and re-enter somewhere else.

2 · Stop sharing the secret

The site keeps the half that’s useless to steal.

what the site stores public key worth nothing to a thief what your device holds private key never sent to the site and each login signs a one-off challenge 1. the site sends a fresh random value 2. the device signs it, gated by your fingerprint, face or PIN 3. the signature is useless next time, so a captured one can’t be replayed A breach of the site now leaks public keys, which are worth nothing.
This already kills the first of the two classic password failures. The site has nothing left worth cracking, and there is no reused secret to carry into your other accounts. It does not yet solve phishing — which is the failure that got you in scene 1.

3 · The move that kills the relay

The attacker’s own domain gets signed into the answer.

the platform signs these together the random challenge the origin and the origin is the one the browser saw in the URL bar, not the one the page claims examp1e.com the browser signs for the domain it is actually on so the relay carries the wrong signature example.com the real site checks it against a key registered for itself and it fails The relay breaks because the fake domain is baked into what it relays. no user could have typed their way past it — there is nothing to type
This is the break that TOTP never had. A one-time code is the same six digits wherever you enter it, so forwarding it works; a passkey signature is bound to where it was produced, so forwarding it produces a signature the real site has no reason to accept.

4 · What it costs

The key not leaving the device is great until the device does.

the fix has a bill, and it is worth naming the original design bound each credential to one authenticator — lose the device, lose the account so passkeys sync, end-to-end encrypted, with your platform account before one password per site, every one of them phishable moves to after one platform account, much better defended Smaller and better defended — but it is still a surface. “unphishable” describes the protocol, not your platform account’s recovery flow
Worth being precise about what moved rather than what vanished: passkeys relocate the trust anchor from every individual site’s password to your platform account. That is a much smaller and much better-defended surface, and it is not no surface — which is why account-recovery design is where most of the remaining difficulty lives.

5 · Keep this card

The whole thing on one index card.

passkey = a key pair the site never gets the private half of + an origin-bound challenge-response ∴ the first half survives a breach… … the second survives you, on a convincing page passwords and one-time codes have neither property, which is why no amount of training closed that hole
Picture to keep: instead of reciting a password, your phone signs a one-off note saying “yes, this is me, and I am standing at https://example.com” — and the signing pen never goes to the site, so there is nothing to recite into the wrong page.

Why it exists

A text says your bank has flagged a payment. The link looks right, the page looks right, so you type your password — and then the site asks for the 6-digit code from your authenticator app, which feels reassuring, so you type that too. Somewhere else, in real time, both were being retyped into the real bank’s login page. You did everything the security advice told you to do, including the second factor, and you were still robbed. That’s the scenario passkeys were built to make impossible, and it’s worth noticing why it worked: every single thing you were asked for was a thing you could type.

Every password-based login has the same shape: you type a secret, the site checks it against a stored hash, and if they match you’re in. That model has two failure modes that no amount of UX polish ever fixed.

The first is the breach. The site stores something derived from your password. If they hash it well, attackers crack a fraction. If they hash it badly — or in plaintext, which still happens — attackers crack all of it. Any password you reuse is now a key to other accounts.

The second, worse failure is phishing. You don’t even need a breach. You just need a fake login page that looks convincing. The user types the real password into the wrong site and hands it over. Two-factor codes via SMS or TOTP help, but they’re also typeable, so a phishing site that proxies through to the real site in real time can catch the code too. This is a well-worn path into modern accounts — not brute force, but social engineering plus a look-alike domain, exactly as in the bank text above.

Passkeys exist because the underlying problem is the shared secret itself. As long as authentication is “type a thing the server already knows,” the thing can be stolen, leaked, or fooled out of you. The fix is to stop sharing the secret at all.

Why it matters now

Apple, Google, and Microsoft shipped consumer passkey support across their platforms through 2022–2023, and large sites — GitHub and Amazon in 2023, Shopify since — added them. So this stops being theory the next time a site you use prompts you to “create a passkey,” and it stops being optional the first time you have to add WebAuthn to a product yourself.

The specific thing that changed is the price of a convincing fake. Building a look-alike login page, writing flawless copy in the target’s language, and running a real-time proxy that relays the victim’s password and one-time code to the genuine site used to take some skill; off-the-shelf phishing kits and generative tools have lowered the bar on each of those steps. Defenses that depend on the user noticing something is off degrade as the fakes get better. A credential that cannot be handed over — because the protocol never produces anything the user could type into the wrong page — doesn’t degrade at all. That’s the argument for a structural defense over a behavioural one.

The short answer

passkey = a key pair the site never gets the private half of + origin-bound challenge-response over WebAuthn

Picture to keep: instead of reciting a password, your phone signs a one-off note saying “yes, this is me, and I am standing at https://example.com” — and the signing pen never goes to the site, so there is nothing to recite into the wrong page.

A passkey is a public/private keypair created for one site. The site stores only the public key. To log in, the site sends a random challenge; your device signs it with the private key; the site verifies with the public key. The private key is never sent to the site, and the browser ties the signature to the exact origin you’re on, so a fake site gets the wrong signature.

How it works

Follow the fake bank page from the hook, and fix it one break at a time.

Naive fix: stop sending a secret; send a signature. When you “create a passkey” on a site, the browser generates a fresh keypair scoped to that site’s origin (https://example.com). The private key is stored in the platform’s secure store — TPM on Windows, Secure Enclave on Apple devices, equivalent on Android — and is never handed to the site. The site keeps only the public key, plus a credential ID it echoes back later to say “use this passkey.” Now a breach of the site leaks public keys, which are worth nothing to an attacker.

But that alone doesn’t stop replay. If logging in meant sending a fixed signature, anyone who captured it once could resend it forever. Fix: sign a fresh challenge. The site sends a random value; the browser asks the platform to sign it, gated by a local user verification step (fingerprint, face, PIN). Each login produces a signature that is useless the next time.

But the phishing site can still relay. This is the break that kills TOTP: the fake page simply forwards whatever the real site asks for, in real time, and passes your answer along. If all the device signed were the challenge, the fake page would hand that signature straight to the real bank and be logged in as you. Fix: bind the signature to the origin. The authenticator signs the challenge together with the browser’s own record of which site this is — crucially, the origin the browser saw in the URL bar, not the one the page claims — and the server checks both the signature and that the origin and site identifier are the ones it expects. On examp1e.com, the browser signs for examp1e.com, and the real site verifies that signature against a key registered for example.com, and it fails. The relay breaks because the attacker’s own domain is baked into the thing being relayed, and no user could have typed their way past it.

This is the standard called WebAuthn (the browser API) running on top of CTAP2 (how the browser talks to the authenticator), both shepherded by the FIDO Alliance. “Passkey” is the consumer-friendly name for a passwordless credential of this kind. Some are synced across your devices via your platform account (iCloud Keychain, Google Password Manager) so losing your phone doesn’t lock you out; others are device-bound and stay on one authenticator.

That sync is the last break in the chain, and the seam worth showing. The key never leaving the device is great until the device goes in a river. Earlier FIDO2 deployments commonly used device-bound credentials — security through non-portability — and ordinary users hit a wall: lose the device, lose the account. Fix: end-to-end encrypted sync, so passkeys roam with your platform identity. And the cost of that fix: if your Apple ID or Google account is compromised, your passkeys travel with it. The honest read is that passkeys move the trust anchor from “every individual site’s password” to “your platform account,” which is a much smaller and much better-defended surface — but it is a surface, and “unphishable” describes the protocol, not your iCloud recovery flow.

There’s no published figure for what fraction of breaches passkeys would have prevented, and the claim doesn’t need one. The verifiable statement is the narrower one: the challenge-response is origin-bound, so credential phishing as a class doesn’t work against it.

You started with passkey = a key pair the site never gets the private half of + origin-bound challenge-response over WebAuthn. Which of those two halves did the fake bank page in the hook actually run into? — the second. The site only ever holding the public half is what survives a breach; binding the signature to the origin is what survives you, on a bad day, on a convincing page. Passwords and one-time codes have neither property, which is why no amount of user training ever closed that particular hole.

Going deeper