WebAuthn/Passkeys Implementation in Detail: A Security Perspective
AI generated
OWASP
0x00
Security · Authentication · WebAuthn · FIDO2
WebAuthn/Passkeys
implementation in detail from a security perspective

Passwords share one structural flaw: the server and the user hold the same secret, and every place that secret ever gets typed or stored becomes a potential attack surface. WebAuthn solves this at the root by replacing shared secrets entirely with asymmetric public-key cryptography. Understanding why passkeys are not just more convenient but structurally more secure than passwords requires walking through the registration and authentication ceremony in detail.

16 min read WebAuthn · Passkeys · FIDO2 Public-key cryptography · Phishing resistance

1. The core principle: public-key cryptography instead of shared secrets

In a classic password-based login, both the user and the server know the same secret, with the server ideally storing only a hash of it. Even so, the plaintext password has to be transmitted on every single login attempt, opening up attack surfaces like phishing pages, compromised network paths, or insecure storage in the browser.

WebAuthn works fundamentally differently: during registration, the user's device generates a cryptographic key pair consisting of a private and a public key. The private key never leaves the device or its security chip, while the public key is transmitted to and stored on the server. On every authentication, the device signs a server-issued challenge with the private key, and the server verifies that signature against the stored public key, without a secret value ever leaving the device.


// Registration ceremony: creating a PublicKeyCredential in the browser
async function registerPasskey(challengeFromServer, userId, userName) {
  const publicKeyOptions = {
    challenge: challengeFromServer, // Uint8Array, generated per request by the server
    rp: { name: 'Example Shop', id: 'example-shop.com' },
    user: {
      id: userId,          // Uint8Array, stable server-side user ID
      name: userName,       // e.g. email address
      displayName: userName,
    },
    pubKeyCredParams: [
      { type: 'public-key', alg: -7 },   // ES256
      { type: 'public-key', alg: -257 }, // RS256 as a fallback
    ],
    authenticatorSelection: {
      userVerification: 'required',       // PIN/biometric required
      residentKey: 'required',            // discoverable credential for passkey
    },
    timeout: 60000,
    attestation: 'none',
  };

  const credential = await navigator.credentials.create({ publicKey: publicKeyOptions });
  // credential.response holds the public key -- send it to the server
  return credential;
}

2. The registration ceremony in detail

The registration flow, called a ceremony in the WebAuthn specification, starts with the server generating a random, sufficiently long challenge and sending it to the browser, along with information about the relying party, meaning the service itself, and the logged-in user. The browser passes this data to the authenticator through the navigator.credentials.create() API, meaning either a hardware security key, a platform's built-in security chip on a phone or laptop, or a passkey cloud sync provider.

The authenticator requests local verification from the user, for example a fingerprint, face recognition, or a device PIN, then generates a fresh key pair scoped specifically to this relying party and signs an attestation proving the public key genuinely came from a real authenticator. The browser sends the public key, the signed challenge, and metadata such as the credential ID back to the server, which, after verification, stores this data permanently linked to the user account.

3. The authentication ceremony in detail

For an actual login, the server again generates a fresh, random challenge and sends it to the browser along with the list of the user's known credential IDs. The navigator.credentials.get() API passes this challenge to the authenticator, which identifies the matching key pair generated during registration by its credential ID.

After another round of local user verification, the authenticator signs the challenge together with additional security-relevant data, such as the actual origin of the calling page, using the private key, and sends the signature back to the browser. The server verifies that signature against the public key stored at registration time along with the origin claim, and grants access on success, without ever transmitting a reusable secret.

4. Phishing resistance as the central security advantage

The decisive security gain over passwords, and even over one-time-code-based second factors, lies in a WebAuthn credential being structurally bound to the exact origin of the site it was registered on. On every authentication, the browser automatically passes the calling page's actual origin to the authenticator, which refuses to sign the challenge the moment that origin does not match the one recorded at registration.

If a user visits a phishing page under a similar but distinct domain, say example-shop-login.com instead of example-shop.com, the authenticator detects the origin mismatch automatically and refuses any interaction, without the user ever having to carefully scrutinize the domain themselves. This mechanism differs fundamentally from SMS or authenticator-app one-time codes, which a user can accidentally type into a phishing page as well, because the codes themselves carry no origin binding whatsoever.

5. Discoverable credentials: the difference between WebAuthn and true passkeys

While WebAuthn has existed as a web API for years, the newer term passkey specifically refers to so-called discoverable credentials, where the reference to the key pair lives directly on the authenticator instead of needing to be sent by the server on every login. This enables a login flow where the user does not even need to type a username, since the browser can directly surface matching, locally stored credentials.

Modern operating systems such as iOS, Android, and Windows additionally support cloud syncing of these discoverable credentials through the respective platform account, so a passkey registered once becomes automatically available on every device tied to the same user. This syncing solves the earlier core problem of hardware security keys, namely losing access after losing the physical device, without weakening the cryptographic security of the underlying mechanism.

6. Conditional UI: blending passkeys into existing login forms

A particularly user-friendly extension of WebAuthn is conditional UI, where an existing login form with a classic username and password field stays exactly as it is, but the browser additionally surfaces matching, locally stored passkeys directly in the username field's autofill dropdown. The user can then either type a password or log in with one click on the suggested passkey via biometrics, without the page needing two separate forms or buttons.

Technically, conditional UI is enabled through the autocomplete="username webauthn" attribute on the input field along with the mediation: 'conditional' option when calling navigator.credentials.get(), with the request already issued in the background as the page loads and only resolved once the user actually interacts with the autofill suggestion. This approach makes gradually migrating existing password forms considerably easier, since no structural change to the visible form is required.

7. Fallback strategy for users without a WebAuthn-capable device

Despite broad support across modern operating systems and browsers, there are still users with older devices, restrictive corporate environments, or specific accessibility needs who cannot use WebAuthn. A production-ready system therefore needs a fallback path, one that must not itself become the weakest link in the security chain.

A well-proven fallback is a password combined with an additional second factor, such as a TOTP app, rather than plain password login without extra protection. It is equally important not to quietly make the fallback path easier than the WebAuthn path, since an attacker will deliberately target whichever of the two paths is weaker. Some systems therefore offer WebAuthn as a mandatory second factor on top of the password rather than treating it as a full password replacement, until passkey adoption reaches a sufficiently high level.

8. Critical server-side implementation details

Server-side, every challenge must be random, sufficiently long, and valid for exactly one authentication attempt, typically stored short-lived in a server-side session and invalidated immediately after use. Origin verification must never be left to the client; it has to happen server-side against the client data signed by the authenticator, since a purely client-side check can be trivially bypassed by an attacker.

Equally important is maintaining a signature counter per credential, which should return an increasing value on every successful authentication. A stagnant or decreasing counter value can indicate a cloned credential, for example from a compromised hardware authenticator, and should be treated as a warning sign server-side, though modern cloud-synced passkey implementations sometimes no longer increment this counter reliably.

9. Conclusion: WebAuthn as a structurally superior authentication approach

WebAuthn does not fix the core problem of password-based systems through extra rules or complexity requirements, but through a fundamentally different cryptographic approach, one where a reusable secret never leaves the user's device. The tight binding to the actual origin makes phishing structurally ineffective, instead of relying solely on user vigilance the way passwords and one-time codes both do.

For a production-ready implementation, what matters beyond the ceremony logic itself is server-side rigor in challenge generation and origin verification, plus a well-designed fallback strategy for users without a compatible device that is not allowed to be weaker. Teams that implement these pieces cleanly reach a security level that classic passwords, even under the strictest password policy, practically cannot match.

Aspect Password One-time code (SMS/app) WebAuthn/passkey
Secret stored on server Hash stored No persistent secret Public key only
Phishing resistance None Low, code can be typed manually anywhere Structural, bound to origin
Reusability if stolen High Time-limited None, signature unique per challenge
User friction Recall and type required Extra step required Biometric/PIN, often one tap
Device loss No direct risk No direct risk Cloud sync significantly reduces risk

Mironsoft

Security audits, OWASP-compliant hardening, and secure architecture

Applications that actually hold up against a real attack attempt?

We review existing applications for classic OWASP vulnerabilities, insecure authentication, and missing input validation, then build an architecture that structurally reduces attack surface instead of just patching individual symptoms.

Security Audit

Systematically checking OWASP Top 10, auth flows, and input validation for vulnerabilities.

Secure Architecture

Building rate limiting, encryption, and access controls correctly from the ground up.

Incident Readiness

Establishing logging, monitoring, and response processes for when things go wrong.

10. Summary

WebAuthn/Passkeys implementation at a glance

Core principle

The private key never leaves the device; only the public key gets shared.

Ceremony

Registration generates a key pair; authentication signs a fresh server challenge.

Security advantage

Origin binding makes phishing pages structurally ineffective.

In practice

The fallback for users without a WebAuthn device must not be weaker.

11. FAQ: WebAuthn/Passkeys implementation at a glance

1What is the fundamental difference between WebAuthn and passwords?
WebAuthn uses asymmetric public-key cryptography where the private key never leaves the device. Passwords, by contrast, are a shared secret that has to be transmitted on every login.
2What exactly happens during the registration ceremony?
The server sends a random challenge, the device generates a new key pair in response, signs an attestation, and sends only the public key plus metadata back to the server.
3How does the authentication ceremony differ from registration?
No new key pair is generated during authentication. Instead, the authenticator signs a fresh server challenge using the private key already generated during registration.
4Why is WebAuthn considered phishing-resistant?
Because the browser automatically passes the actual origin to the authenticator on every authentication, and the authenticator refuses to sign the moment that origin does not match the one recorded at registration.
5What is the difference between WebAuthn credentials and passkeys?
Passkeys are discoverable credentials whose key reference lives directly on the authenticator and is often synced across devices through a platform account. Classic WebAuthn credentials have to be sent by the server on every login.
6How does passkey syncing solve the lost hardware key problem?
Since discoverable credentials sync through the platform account, access survives the loss of a single device as long as another synced device remains available.
7What fallback does a system need for users without a WebAuthn device?
A well-proven approach is a password combined with an additional TOTP second factor; it is important not to make this fallback weaker than the WebAuthn path itself.
8What does the server need to get right during challenge generation?
The challenge must be random, sufficiently long, and valid for exactly one attempt. It should be stored short-lived server-side and invalidated immediately after use.
9Why is server-side origin verification so critical?
A purely client-side check can be trivially bypassed by an attacker. The server-side check against the client data signed by the authenticator is the actual security anchor.
10What does a stagnant signature counter indicate?
A counter value that fails to increase on a new authentication can indicate a cloned credential, though this signal should not be overinterpreted with cloud-synced passkeys, where the mechanism sometimes behaves differently.