Passkey Town

mosajjal1 pts1 comments

Passkey Town | How passkeys and WebAuthn actually work | Fenko

Drag to orbit, scroll to zoom, click any building. Space plays, arrow keys step.<br>Open full screen &rarr;

What you are looking at

Four parties, and the whole protocol makes sense once you know who trusts whom.

01<br>Alicethe user<br>A passkey ceremony needs a live human gesture. Nothing here works from a script running at 3am.

02<br>Authenticatorher phone<br>The secure element. Generates key pairs, keeps the private halves, signs on request. There is no export path.

03<br>Clientthe browser<br>Enforces domain scoping and writes the origin into clientDataJSON, where page JavaScript cannot reach it.

04<br>Bob's serverthe relying party<br>Issues challenges, verifies signatures, stores public keys. A dump of that database is not worth much.

The client is the load-bearing part. It is the only party that knows for certain<br>which site the user is actually on, and it writes that fact into the signed data<br>where an attacker cannot touch it. That single design choice is why passkeys<br>resist phishing and passwords do not.

Why the phishing flow matters

Run the third walkthrough. Mallory gets three attempts and loses all three, each<br>for a different reason:

At the client. A page on a lookalike domain cannot request an rpId it<br>does not own. The call fails before the authenticator is ever woken up.

At the authenticator. Asking under its own domain is allowed, but no<br>credential was ever registered there, so there is nothing to return.

At the server. Even granting the attacker a signature by some other means,<br>clientDataJSON still records the origin the browser was on, and that string<br>is inside the signature. Editing it breaks the signature. Re-signing needs a<br>key that never left the secure element.

A password would have been handed over at step one. So would an SMS code, a TOTP<br>code, or a push approval — an attacker proxying the real site only needs a few<br>seconds. Passkeys move the judgement call off the human and onto the browser,<br>and the browser is not fooled by a homoglyph.

The last flow is real

&ldquo;Try it for real&rdquo; is not a cartoon. It calls navigator.credentials.create()<br>against your actual authenticator, decodes authenticatorData byte by byte,<br>then converts the DER signature to raw r‖s and verifies it with WebCrypto<br>against the public key it stored. Nothing is sent anywhere: the public key<br>lives in localStorage and there is no server involved.

It opens in its own tab, and that is not a convenience. Browsers refuse to<br>create a passkey inside an embedded frame: Chrome rejects the call and Safari<br>blocks it entirely, on the grounds that a credential should only ever be<br>created by the site showing in the address bar. The walkthrough above is<br>embedded, so the restriction applies to it — a small live demonstration of the<br>same origin-binding principle the phishing flow is about.

That does mean you end up with a real passkey scoped to this domain, saved<br>wherever your device saves them. &ldquo;Forget it&rdquo; clears our copy of the public key,<br>but the passkey itself lives in your password manager or secure element — remove<br>it there if you want it gone.

Deliberately not modelled

CBOR and COSE encoding, attestation statement formats, the hybrid transport that<br>makes phone-as-authenticator work, and conditional UI. All of them matter, and<br>none of them help on a first pass. The signature verification handles ES256<br>only; RS256 credentials register fine but the in-browser check will say it<br>skipped them.

If you want a passkey manager that keeps credentials on your own devices rather<br>than in someone else&rsquo;s cloud, that is what Fenko Vault is for.

This site uses cookies. By continuing to use this website, you agree to their use.

I Accept

passkey browser signature domain public site

Related Articles