Skip to main content
Security & Privacy

Passkeys vs Passwords: How WebAuthn Actually Replaces the Password

A grounded look at how passkeys, FIDO2, and WebAuthn work, why they kill phishing, and the real tradeoffs nobody mentions in 2026.

By · · 12 min read

For about thirty years the answer to “how do I prove who I am online” was the same: type a secret string you also stored in your head. Passkeys break that pattern, and not in a marketing way. They change the actual cryptography of what happens when you log in. This post walks through how that works, where it genuinely beats passwords, and the rough edges that still trip people up in 2026.

What a passkey actually is

A passkey is a public/private key pair. That’s the whole thing. When you create one for a site, your device generates two mathematically linked keys. The private key stays on the device, locked behind your hardware’s secure element. The public key gets sent to the server and stored next to your account.

The asymmetry is the point. The server can verify a signature made by the private key, but it can never reproduce that signature itself, because it doesn’t have the private key. Compare that to a password, where the server has to store something derived from your secret in order to check it later. Even a properly salted bcrypt or Argon2 hash is a derivative of a shared secret. With a passkey there’s no shared secret at all. The server’s copy is useless to an attacker who steals the database.

Each passkey is scoped to one site. The browser ties it to the site’s origin (its Relying Party ID, usually the domain). A passkey created for github.com will not produce a valid signature for g1thub.com, and the browser won’t even offer it. Hold that thought, because it’s the mechanism behind the anti-phishing claim later.

If you’ve used a hardware security key for SSH or a YubiKey for 2FA, you already know roughly how this feels. Passkeys are the same FIDO2 primitive, just made the primary credential instead of a second factor.

The WebAuthn ceremony, step by step

WebAuthn is the browser API that exposes all of this. The spec calls each login flow a “ceremony.” There are two: registration and authentication. Both are challenge-response, and the server never sees a private key.

Registration

When you sign up or add a passkey to an existing account:

  1. The server generates a random challenge and sends it to the browser, along with the Relying Party info and your user handle.
  2. The browser hands that to the authenticator (your phone’s secure enclave, Windows Hello, a YubiKey, whatever).
  3. The authenticator verifies you with a local gesture (Face ID, fingerprint, PIN) and generates a fresh key pair scoped to that origin.
  4. It signs the challenge with the new private key and returns the public key plus the signed attestation.
  5. The server stores the public key and a credential ID against your account.

Here’s the shape of it in the browser API:

// Registration - the server already sent `challenge` and `user`
const credential = await navigator.credentials.create({
  publicKey: {
    challenge,                       // random bytes from the server
    rp: { name: "Example", id: "example.com" },
    user: { id: userIdBytes, name: "[email protected]", displayName: "Ada" },
    pubKeyCredParams: [
      { type: "public-key", alg: -7 },   // ES256
      { type: "public-key", alg: -257 }, // RS256
    ],
    authenticatorSelection: {
      residentKey: "required",       // makes it a discoverable passkey
      userVerification: "required",
    },
  },
});
// Send credential.response (attestation + public key) back to the server

That random challenge matters. It has to be unguessable and single-use, which is exactly the property a good random token generator gives you. If you’re building the server side and need to mint challenges, our Secure Token Generator is the same class of CSPRNG-backed value you’d want feeding crypto.randomBytes in production.

Authentication

Logging in later is the mirror image:

  1. Server sends a new random challenge.
  2. Browser asks the authenticator to sign it with the private key for that origin.
  3. You confirm with a biometric or PIN.
  4. Authenticator returns the signature; server verifies it against the stored public key.
// Authentication
const assertion = await navigator.credentials.get({
  publicKey: {
    challenge,                  // fresh random bytes
    rpId: "example.com",
    userVerification: "required",
    allowCredentials: [],       // empty = let the user pick a discoverable passkey
  },
});
// Server checks assertion.response.signature against the stored public key

No password travels the wire. No code gets typed. The signature is only valid for this one challenge, on this one origin, and it expires the moment it’s used.

Why this kills phishing and credential stuffing

Two of the most common ways accounts get compromised stop working against passkeys, and it’s worth being precise about why.

Phishing. A phishing attack relies on tricking you into handing your secret to a lookalike site. With a passkey there’s nothing to hand over. The browser binds the signature to the origin it’s actually talking to. If you land on paypa1.com, the authenticator will not sign with your paypal.com key, because the origins don’t match. The browser doesn’t even surface the passkey. The attacker gets nothing usable, even if their page is a pixel-perfect clone. This is structurally different from TOTP. A real-time phishing proxy can sit between you and the real site, capture the six-digit code from your authenticator app, and replay it within the 30-second window. Passkeys don’t have a code to capture.

Credential stuffing. This attack reuses passwords leaked from one breach against other sites, betting on reuse. It works because passwords are portable secrets. A stolen public key is worthless: you can’t sign with it, and it only ever applied to one site anyway. There’s no list of reusable secrets to stuff.

That said, passkeys don’t make you immune to everything. Malware already running on your unlocked device can abuse an authenticated session. Account-recovery flows are often the soft underbelly (more on that below). And social engineering against a support desk doesn’t care what your login crypto looks like. Passkeys remove a whole category of attack; they don’t end the war.

Here’s the comparison laid out plainly:

AttackPassword (+ TOTP)Passkey
Database breach leaks credentialsHashes can be cracked offlinePublic key alone is useless
Phishing page captures inputTOTP relayable in real timeOrigin mismatch blocks signing
Credential stuffing / reuseWorks if you reuse passwordsNo portable secret exists
Keylogger on deviceCaptures password and codeNothing typed to capture
Malware in active sessionVulnerableStill vulnerable
Account recovery abuseVulnerableOften still vulnerable

The authenticator: platform vs roaming

The thing that holds your private key is the authenticator, and there are two flavors.

Platform authenticators are built into the device. Face ID and Touch ID on Apple hardware, Windows Hello on a PC, the fingerprint sensor on an Android phone. They talk to WebAuthn directly through the OS. Convenient, always with you, and the most common way people meet passkeys.

Roaming authenticators are separate hardware you plug in or tap: a YubiKey 5, a Google Titan key, a SoloKey. They speak to the browser over USB, NFC, or Bluetooth using a protocol called CTAP2 (Client to Authenticator Protocol). The same CTAP2 link is what powers cross-device sign-in, where your phone acts as a roaming authenticator for a nearby laptop over Bluetooth after you scan a QR code.

Roaming keys are the choice for people who want the private key to physically never leave a dedicated piece of hardware. The downside is obvious: it’s one more object to carry and not lose. For most users a platform authenticator backed by a synced credential store is the realistic default.

Synced passkeys vs device-bound

This is the split that causes the most confusion, and it’s the most important decision in how passkeys actually behave for you.

Device-bound passkeys never leave the authenticator that made them. A passkey generated on a YubiKey lives and dies on that YubiKey. High assurance, because the private key has exactly one home. Also high risk if that home gets lost, because there is no copy anywhere.

Synced passkeys are backed up and copied across your devices through a credential manager:

  • iCloud Keychain syncs passkeys across your Apple devices, end-to-end encrypted, restorable when you sign into a new iPhone or Mac.
  • Google Password Manager does the same across Android and Chrome.
  • Windows Hello historically leaned device-bound, though Microsoft has been moving toward synced passkeys tied to your Microsoft account.
  • Bitwarden and 1Password are cross-platform managers that store passkeys and sync them regardless of OS, which sidesteps the walled-garden problem.

Synced passkeys trade a sliver of theoretical security for enormous practical resilience. The argument against syncing is that your private key now exists in more than one place and rides on the security of your cloud account. The argument for it is that the alternative - losing every credential when you drop your phone in a lake - is a far more likely failure mode for normal humans. FIDO’s own guidance accepts synced passkeys precisely because device-bound-only adoption stalls on recovery anxiety.

If you run a service and want to know which kind a user registered, the authenticator data flags it. You can require device-bound for high-value actions and accept synced for everyday login. That tiering is sensible.

The real-world gaps

Now the part the launch blogs skip.

A passkey is only as strong as the worst way to bypass it. Plenty of sites that proudly added passkey support still let you reset access with an emailed magic link or an SMS code. If your recovery path is a text message, an attacker who SIM-swaps you walks straight past all that elegant cryptography. Passkeys raise the floor of your login, but recovery often keeps a trapdoor in it. When you set up a passkey-protected account, look at how recovery works before you trust it with anything important.

Cross-ecosystem syncing is still messy

Within Apple’s world or within Google’s world, sync is smooth. Between them it isn’t. There’s no native “copy my passkeys from iCloud Keychain to Google Password Manager” button, and there probably won’t be one soon, because neither company is in a hurry to make leaving easy. The Credential Exchange Protocol that’s supposed to standardize this is rolling out slowly. Until it lands everywhere, a third-party manager like Bitwarden or 1Password is the cleanest way to hold one passkey set that works on every device you own.

”What if I lose my phone”

This is the question everyone asks, and the honest answer is: it depends entirely on what you set up beforehand.

  • Synced passkey, single ecosystem: sign into your replacement device, your passkeys come back. Mostly painless.
  • Device-bound passkey on a lost key with no backup registered: that credential is gone, and you’re at the mercy of the site’s recovery flow.
  • No second authenticator anywhere: you can get locked out hard.

The fix is boring and effective: register at least two authenticators on accounts you care about. A platform passkey on your phone plus a roaming key in a drawer covers the common disaster. Treat it like a spare house key.

Coverage is still uneven

Big platforms support passkeys now - Google, Apple, Microsoft, GitHub, Amazon, PayPal. The long tail of smaller sites doesn’t. Plenty still offer passwords only, or offer passkeys as a bolted-on second factor rather than a true replacement. You will be living in a mixed world for years.

Where passwords still hang on

Passwords aren’t dead, and pretending otherwise sets you up to be unprepared.

  • Recovery and fallback. As above, most passkey deployments still keep a password or backup code as the break-glass option. You’ll keep generating strong ones.
  • Legacy systems. Enterprise apps, old VPNs, embedded device admin panels, anything that predates WebAuthn. These aren’t getting passkeys.
  • Shared and headless accounts. Service accounts, machines, kiosks, and accounts a team passes around don’t map cleanly onto a per-person biometric model.
  • Sites that just haven’t built it. The majority of the web, still.

So the practical stance for 2026 is hybrid. Use passkeys wherever a site offers them as a real login method. Keep a password manager for everything else, and make those passwords long and random rather than memorable. When you do need a fallback password, generate it instead of inventing it: our Password Generator produces high-entropy strings, and if you want to sanity-check something you already use, the Password Strength Checker will tell you how it actually holds up. And where passkeys aren’t available but a site supports app-based 2FA, a TOTP Generator is still a meaningful step up from password-only, even if it’s the weaker cousin of a passkey.

Summary

A passkey is a per-site public/private key pair where the private half never leaves your authenticator and the server only ever holds the public half. The WebAuthn ceremony is a challenge-response signed locally after a biometric or PIN, with no shared secret crossing the wire. That design structurally defeats phishing, because signatures are bound to the real origin, and credential stuffing, because there’s no portable secret to reuse or leak. Authenticators come as platform (Face ID, Windows Hello) or roaming (YubiKey), and credentials are either synced for resilience or device-bound for maximum assurance. The genuine tradeoffs are account recovery still being a soft target, cross-ecosystem syncing being half-finished, and the lost-device problem hinging on whether you registered backups in advance. Passwords stick around as fallback, in legacy systems, and on the long tail of sites that haven’t caught up. Adopt passkeys where they’re real, keep a manager for the rest, and register a second authenticator before you need it.

Tools mentioned in this article

  • Password Generator - Generate cryptographically secure random passwords with configurable length, character types and entropy display.
  • Password Strength Checker - Check password strength with entropy calculation, pattern detection and common password matching.
  • Secure Token Generator - Generate cryptographically secure random tokens in base64url, hex, alphanumeric or UUID v4 format.
  • TOTP Generator - Generate time-based one-time passwords (TOTP) from a base32 secret with live 30-second countdown.

Related articles