The mental model
Before the code, the shape of the thing. Three actors, one key pair per site, and two ceremonies.
The three actors
- Relying party (RP)
-
The website — identified not by its pretty name but by its RP ID,
a domain name like
passkeydemo.com. Every credential is scoped to an RP ID — a later page on this site digs into exactly what that scoping prevents. - Authenticator
- Whatever holds the private key — Touch ID, Windows Hello, a hardware security key, or your phone. The private key is generated on the authenticator and never leaves it, not even to the browser.
- Browser
- The go-between. It talks to the authenticator via the WebAuthn API, and to the server over HTTPS. It's also the thing enforcing that a credential can only be used for the origin it was created on — more on why that matters below.
One key pair, per site, per authenticator
Registering a passkey generates a fresh public/private key pair scoped to one RP ID. The private key stays on the authenticator. The public key — useless to an attacker without the private half — is the only thing the server ever stores.
The two ceremonies
Registration Authentication
Registration
The server sends a random challenge and some rules. The authenticator generates a new key pair, signs the challenge with the new private key, and hands back the public key plus that signature. The server verifies the signature, then stores the public key. Walked through in full on the Registration page.
Authentication
Same shape, reversed key usage: a new challenge, signed this time with the existing private key, verified by the server against the public key it already has on file. See the Authentication page.
Where the phishing resistance actually comes from
A password is just a string — you can be tricked into typing it into a lookalike
site, and it'll work there exactly as well as on the real one. A passkey can't be
phished the same way, not because it's "more secret," but because of what the
browser does before it ever asks the authenticator to sign anything: it
binds the request to the actual origin the page is loaded from. An authenticator
only ever signs for the origin the browser tells it, and the browser doesn't lie
about that — even if the page's content is a pixel-perfect clone. Register a
passkey on passkeydemo.com, and a convincing fake at
passkeydemo.evil.example simply cannot obtain a valid signature for it,
no matter how good the impersonation is.