The Problem with Passwords

Passwords have three fundamental weaknesses that no complexity requirement can fix: they can be phished (users can be tricked into entering them on fake sites), reused (leading to credential stuffing attacks), and stolen (via database breaches). The industry has known this for years — and WebAuthn is the answer the W3C and FIDO Alliance built.

What Is WebAuthn?

Web Authentication (WebAuthn) is a W3C standard (now part of FIDO2) that enables websites to authenticate users using public-key cryptography instead of passwords. The user proves their identity by performing a local gesture — biometric scan, PIN, or hardware key press — rather than sending a secret over the network.

WebAuthn is supported natively in all major browsers and operating systems. Passkeys are the consumer-friendly name for WebAuthn credentials that can sync across devices via platform ecosystems (iCloud Keychain, Google Password Manager, etc.).

The Cryptographic Foundation

WebAuthn uses asymmetric (public-key) cryptography. During registration:

  1. The user's device generates a unique key pair for your specific site (relying party).
  2. The public key is sent to your server and stored.
  3. The private key never leaves the user's device — ever.

During authentication:

  1. Your server sends a random challenge.
  2. The user authenticates locally (Face ID, fingerprint, PIN).
  3. The device signs the challenge with the private key.
  4. Your server verifies the signature using the stored public key.

There's nothing to phish — the private key is never transmitted, and the key pair is bound to your specific domain, so fake sites can't intercept credentials.

Passkeys vs. Security Keys vs. Platform Authenticators

Type Example Syncs? Portable?
Platform authenticator (passkey) Face ID, Windows Hello, Android biometric Yes (via OS keychain) Within ecosystem
Roaming authenticator YubiKey, FIDO2 hardware key No Any device with USB/NFC
Cross-platform passkey 1Password, Bitwarden passkey storage Yes Cross-ecosystem

Implementing WebAuthn: The Developer Flow

Registration

Your server generates a PublicKeyCredentialCreationOptions object and sends it to the browser. The browser calls navigator.credentials.create(), which prompts the user to authenticate locally and returns a credential containing the public key, credential ID, and attestation data.

You store the credential ID and public key associated with the user's account.

Authentication

Your server generates a PublicKeyCredentialRequestOptions with a fresh challenge and the list of allowed credential IDs for the user. The browser calls navigator.credentials.get(), the user authenticates, and you receive a signed assertion. Verify the signature server-side, and you're done.

Recommended Libraries

  • SimpleWebAuthn (JavaScript/TypeScript) — Full-featured, well-documented, handles both browser and server
  • webauthn4j (Java) — Mature library for Java/Spring applications
  • py_webauthn (Python) — Clean Python implementation
  • go-webauthn (Go) — Popular Go library

UX Considerations

WebAuthn adoption depends heavily on a smooth user experience. Key guidance:

  • Offer passkeys as an option, not a replacement — Until passkey coverage is universal, maintain password fallback.
  • Handle account recovery carefully — If a user loses all their devices, they need a recovery path that doesn't undermine security.
  • Use clear, familiar language — "Sign in with Face ID" is better than "authenticate with WebAuthn credential".
  • Support multiple credentials per account — Users have multiple devices; let them register all of them.

The Bottom Line

WebAuthn and passkeys represent the most significant security improvement available to web developers today. They eliminate the most common attack vectors — phishing, credential stuffing, and breach reuse — with a user experience that's actually simpler than typing a password. If you're building or maintaining an authentication system, passkey support should be on your roadmap now.