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 sends a public key to the server; authentication sends a signature the server verifies against it. Authenticator Browser Server signs challenge registration: public key auth: challenge (forwarded)

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.