Passkeys mostly won and nobody noticed
Phishing-resistant authentication is now the default on major platforms. The remaining problem is account recovery.
Passkeys — WebAuthn credentials synced across a user's devices — are now the default or prominently offered sign-in method on most major consumer platforms. Adoption crossed the threshold where a developer building a new product should consider passwords the legacy option.
why they actually work#
The security property that matters is not "no password to remember." It is origin binding.
A passkey is a keypair. The private key never leaves the authenticator. When you authenticate, the browser signs a challenge, and the signature includes the origin of the site requesting it.
Which means: a phishing site at paypa1.com cannot use a credential registered to paypal.com. Not "the user might notice." Cannot. The browser will not produce a signature for the wrong origin, and the attacker has nothing to replay.
That eliminates the single most successful attack class in consumer security. Password reuse, credential stuffing, real-time phishing proxies that capture TOTP codes — all defeated structurally rather than probabilistically.
the implementation, briefly#
// registration
const cred = await navigator.credentials.create({
publicKey: {
challenge: serverChallenge, // from your server, random, single-use
rp: { name: "README", id: "readme.news" },
user: { id: userId, name: email, displayName: name },
pubKeyCredParams: [{ type: "public-key", alg: -7 }, // ES256
{ type: "public-key", alg: -257 }], // RS256
authenticatorSelection: {
residentKey: "preferred",
userVerification: "preferred",
},
},
});Send the attestation to your server, verify it, store the credential ID and public key against the user.
Do not implement the verification yourself. Use a maintained library — the spec has enough subtleties that a hand-rolled verifier will have a bug, and the bug will be an authentication bypass.
the part that is still hard#
Account recovery. This is the unsolved problem and it is where every real deployment struggles.
If a user loses access to their passkeys, what happens? The options are all imperfect:
- Fall back to email. Now your security is your email provider's security, and the phishing resistance you bought is gone for the recovery path.
- Backup codes. Users lose them or store them insecurely.
- Multiple passkeys on multiple devices. Good, and requires the user to have set that up before the loss.
- Identity verification. Expensive, invasive, and a social engineering target.
The honest position: an authentication system is only as strong as its recovery path, and most passkey deployments have a recovery path that is substantially weaker than the primary path.
That is not an argument against passkeys — the primary path being strong still eliminates the bulk attacks. It is an argument for thinking about recovery as a first-class design problem rather than a fallback you bolt on.
the practical guidance#
Offer passkeys as an option, not a requirement, unless you control the device fleet. Users on older devices, shared computers, or unusual configurations need an alternative.
Allow multiple passkeys per account. A user with a phone passkey and a hardware key has a recovery path that does not weaken the security model.
Do not delete the password immediately. Let users add a passkey alongside, then prompt to remove the password later once they have used the passkey successfully a few times.
Use conditional UI (autofill-style passkey prompts) rather than a separate button. The friction of "which sign-in method" is a real conversion cost and conditional UI removes it.
For enterprise, device-bound keys. Synced passkeys follow the user's cloud account, which is convenient and is a different trust model. Hardware security keys with attestation are the right answer where the threat model warrants it.
the thing that took ten years#
WebAuthn was standardized in 2019 and the underlying FIDO work started earlier. The technology was ready long before adoption happened.
What changed was not the protocol. It was that the platform vendors implemented syncing, which turned "a credential on one device" into "a credential you have," and that removed the objection that killed every previous attempt.
The lesson for anyone building security infrastructure: the cryptography is usually the easy part. The reason things do not get adopted is almost always a user experience problem, and solving it is real work that security people frequently consider beneath them.
— Dom, March 16, 2026