Passkey Authentication: The End of Passwords for Web Applications
Passwords are the oldest and weakest link in web application security. Credential stuffing, phishing, and brute-force attacks exploit the fundamental flaw of password-based authentication: a shared secret that travels across the network and can be intercepted, guessed, or stolen from a database breach. Passkeys, built on the WebAuthn and FIDO2 standards, replace shared secrets with public-key cryptography. The private key never leaves the user's device, and the authentication ceremony is bound to the exact domain of the relying party. For organizations running web applications behind CDN infrastructure, understanding how passkey flows interact with edge proxies, TLS termination, and caching layers is essential to a successful deployment.
How does passkey authentication work?
Passkey authentication uses the Web Authentication API (WebAuthn), a W3C standard that enables browsers and operating systems to perform public-key cryptographic operations on behalf of web applications. A passkey is a FIDO2 credential consisting of a public-private key pair generated by an authenticator, which can be a hardware security key, a platform authenticator built into the operating system, or a synced credential stored in a cloud-backed keychain.
The WebAuthn protocol operates through two ceremonies: registration and authentication. During registration, the relying party (the web application's server) sends a challenge to the browser, which forwards the challenge to the authenticator. The authenticator generates a new key pair, stores the private key internally, and returns the public key along with an attestation object to the server. During authentication, the server sends a new challenge, the authenticator signs the challenge with the stored private key, and the server verifies the signature using the stored public key. No secret is transmitted across the network at any point in either ceremony.
The critical security property of WebAuthn is origin binding. When the authenticator creates a credential, it records the relying party identifier (RP ID), which defaults to the effective domain of the web application. During authentication, the authenticator checks that the requesting origin matches the RP ID before signing the challenge. A phishing site on a different domain cannot obtain a valid signature because the authenticator refuses to use a credential bound to a different origin. This makes passkeys fundamentally phishing-resistant, unlike passwords, SMS codes, or TOTP tokens.
Synced passkeys versus device-bound passkeys
The FIDO Alliance defines two categories of passkeys based on how the private key is stored and whether it can be synchronized across devices.
| Metric | Edge Processing | Origin Processing | Improvement |
|---|---|---|---|
| Latency (p50) | 8–15 ms | 120–300 ms | 15–20x faster |
| Cache Hit Ratio | 85–95% | N/A | Reduces origin load |
| TLS Handshake | 1–5 ms (nearby PoP) | 50–150 ms | 10–30x faster |
| Bandwidth Cost | $0.01–0.04/GB | $0.05–0.12/GB | 3–5x cheaper |
| Availability | 99.99% (multi-PoP) | 99.9% (single DC) | 10x fewer outages |
Synced passkeys store the private key material in a cloud-backed credential manager operated by the platform vendor. Apple stores synced passkeys in iCloud Keychain with end-to-end encryption. Google stores synced passkeys in Google Password Manager. Microsoft stores synced passkeys in the Microsoft account. When a user creates a synced passkey on one device, the credential becomes available on all devices signed into the same platform account. Synced passkeys solve the device-loss recovery problem: losing a phone does not mean losing access to every account.
Device-bound passkeys keep the private key in a hardware authenticator (such as a YubiKey or a platform TPM) that cannot export the key material. Device-bound passkeys provide stronger security guarantees because the private key physically cannot be extracted or duplicated. However, device-bound passkeys require backup authenticators or alternative recovery mechanisms because the credential dies with the device. Enterprise environments that require the highest assurance levels (financial services, government systems) typically mandate device-bound passkeys using FIDO2 hardware security keys.
| Property | Synced Passkeys | Device-Bound Passkeys |
|---|---|---|
| Private key storage | Cloud-backed credential manager (iCloud, Google, Microsoft) | Hardware authenticator (TPM, security key) |
| Cross-device availability | Automatic via platform sync | Requires physical possession of the authenticator |
| Recovery on device loss | Credential survives via cloud backup | Credential lost; backup authenticator needed |
| Key exportability | Synced within vendor ecosystem (E2E encrypted) | Non-exportable by design |
| Attestation level | Self attestation (no hardware guarantee) | Hardware attestation (FIDO Metadata Service) |
| Best for | Consumer applications, SaaS platforms | Enterprise, financial services, government |
| Phishing resistance | Yes (origin-bound) | Yes (origin-bound) |
How CDN edge proxies handle passkey authentication flows
Deploying passkey authentication behind a CDN architecture requires understanding which parts of the WebAuthn flow can be cached and which must be proxied to the origin without modification. The static assets that compose the login page (HTML, CSS, JavaScript bundles, images) are standard cacheable resources that benefit from edge server caching. The WebAuthn API endpoints, however, are dynamic POST requests that must reach the origin server.
CDN edge servers must proxy WebAuthn API requests (typically /webauthn/register/begin, /webauthn/register/complete, /webauthn/authenticate/begin, and /webauthn/authenticate/complete) directly to the origin with specific requirements. The CDN must preserve the Origin header because the server uses this value to validate the RP ID against the requesting domain. The CDN must not modify the response body because WebAuthn responses contain cryptographic material (challenges, attestation objects, assertion signatures) that are invalidated by any byte-level alteration. The CDN must forward cookies or session identifiers that correlate the begin and complete steps of each ceremony.
A typical nginx configuration for a reverse proxy handling WebAuthn endpoints looks like this:
# WebAuthn API endpoints - proxy to origin, no caching
location ~ ^/webauthn/ {
proxy_pass https://origin-backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Origin $http_origin;
# Do not buffer or modify response
proxy_buffering off;
proxy_request_buffering off;
# No caching for challenge-response
add_header Cache-Control "no-store, no-cache, must-revalidate";
add_header Pragma "no-cache";
# CORS headers for cross-origin credential access
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials "true" always;
add_header Access-Control-Allow-Methods "POST, OPTIONS" always;
add_header Access-Control-Allow-Headers "Content-Type, Authorization" always;
}
Security headers require careful configuration for passkey deployment. The Content-Security-Policy header must allow the WebAuthn JavaScript API calls. The Permissions-Policy header must include publickey-credentials-create=self and publickey-credentials-get=self to permit the browser to invoke the WebAuthn API. If these permissions are denied by the CDN's default security header policy, the browser will silently refuse to create or use passkey credentials.
The FIDO2 protocol stack
FIDO2 is the umbrella specification that combines two complementary protocols: WebAuthn (the browser API) and CTAP2 (the Client-to-Authenticator Protocol). WebAuthn defines the JavaScript API that web applications use to interact with authenticators through the browser. CTAP2 defines the communication protocol between the browser (the client) and external authenticators such as USB security keys, NFC devices, or Bluetooth authenticators.
The FIDO2 architecture separates the roles of the relying party (web server), the client (browser), and the authenticator (hardware or platform credential manager). The relying party never communicates directly with the authenticator. All communication flows through the browser, which acts as a trusted intermediary that enforces origin checks and manages transport-layer communication with authenticators. This separation of concerns is what enables passkeys to work across different browsers, operating systems, and authenticator types without requiring relying parties to implement device-specific logic.
Credential storage and the Relying Party ID
The RP ID is the domain identifier that binds a passkey credential to a specific web application. By default, the RP ID is the effective domain of the page that initiates the WebAuthn ceremony. An application hosted at auth.example.com can set its RP ID to example.com (the registrable domain), which allows the passkey to be used on any subdomain of example.com. The RP ID cannot be set to a domain that is not a registrable suffix of the current origin, preventing a subdomain from claiming credentials for an unrelated domain.
This domain binding has direct implications for DNS configuration and CDN deployment. If an organization uses a separate domain for its authentication service (such as login.example.com) and wants passkeys to work across app.example.com and dashboard.example.com, the RP ID must be set to the common parent domain example.com. The zero trust security model must account for the fact that any subdomain under the RP ID domain can potentially request authentication with the passkey.
Attestation and metadata
During registration, the authenticator can include an attestation statement that cryptographically proves the make and model of the authenticator hardware. Relying parties can verify attestation against the FIDO Metadata Service (MDS), a centralized repository of authenticator metadata maintained by the FIDO Alliance. Attestation verification is most relevant for enterprise deployments that need to enforce policies about which authenticator models are acceptable (for example, requiring FIPS 140-2 validated security keys for government applications).
Most consumer applications should request attestation: "none" during registration because attestation verification adds complexity without meaningful security benefit for non-regulated use cases. Requesting attestation also raises privacy concerns because the attestation certificate identifies the authenticator model, which can be used as a fingerprinting signal. The compliance requirements of the application determine whether attestation verification is necessary.
Implementing passkey authentication on the server
Server-side implementation of WebAuthn requires a library that handles the cryptographic verification of registration and authentication responses. The server must generate cryptographically random challenges, validate the authenticator's response against the stored public key, and manage credential storage. The following example shows the core registration flow using a Node.js server with the @simplewebauthn/server library:
// Registration: Generate challenge
const options = await generateRegistrationOptions({
rpName: 'Example Application',
rpID: 'example.com',
userID: user.id,
userName: user.email,
attestationType: 'none',
authenticatorSelection: {
residentKey: 'required', // Discoverable credential (passkey)
userVerification: 'preferred', // Biometric/PIN when available
},
supportedAlgorithmIDs: [-7, -257], // ES256, RS256
});
// Store challenge for verification
await challengeStore.set(user.id, options.challenge);
// Registration: Verify response
const verification = await verifyRegistrationResponse({
response: attestationResponse,
expectedChallenge: storedChallenge,
expectedOrigin: 'https://example.com',
expectedRPID: 'example.com',
});
if (verification.verified) {
// Store credential
await credentialStore.save({
credentialID: verification.registrationInfo.credentialID,
publicKey: verification.registrationInfo.credentialPublicKey,
counter: verification.registrationInfo.counter,
userID: user.id,
transports: attestationResponse.response.getTransports(),
});
}
The supportedAlgorithmIDs parameter specifies which cryptographic algorithms the server accepts. -7 corresponds to ES256 (ECDSA with P-256 and SHA-256), which is the most widely supported algorithm across authenticators. -257 corresponds to RS256 (RSASSA-PKCS1-v1_5 with SHA-256), which provides backward compatibility with older Windows Hello implementations. The server must store the credential public key, credential ID, and signature counter for each registered passkey.
Security considerations for passkey deployments
While passkeys eliminate the attack surface of password-based authentication, they introduce new security considerations that infrastructure teams must address.
Challenge freshness is critical. Each WebAuthn ceremony must use a unique, cryptographically random challenge with a short expiration window (typically 60 to 120 seconds). The challenge must be stored server-side and validated exactly once. Reusing challenges or accepting expired challenges enables replay attacks. CDN edge servers must not cache challenge-generation endpoints, and rate limiting should be applied to prevent challenge enumeration attacks.
Signature counter validation prevents authenticator cloning. Each time an authenticator performs an authentication ceremony, it increments a counter. The server stores the last-seen counter value and rejects any authentication where the counter is not strictly greater than the stored value. If the counter goes backward or stays the same, the server should flag the credential as potentially compromised. This check is most effective with device-bound passkeys where the counter is maintained in tamper-resistant hardware.
The WAF layer at the CDN edge should include rules specific to WebAuthn traffic. Rate-limit registration attempts per IP address and per user account to prevent credential stuffing of passkey registrations. Monitor for anomalous patterns such as rapid registration of many credentials from a single IP, which may indicate an account takeover attempt. The bot management system should allow legitimate WebAuthn API calls while blocking automated tools that attempt to enumerate valid credential IDs.
Cross-device authentication and the hybrid transport
FIDO2 CTAP2 defines a hybrid transport mechanism for cross-device authentication. When a user needs to authenticate on a laptop that does not hold their passkey, the laptop's browser generates a QR code containing a one-time pairing key. The user scans this QR code with their phone, which holds the passkey. The phone and laptop establish a direct communication channel over Bluetooth Low Energy (BLE) to complete the authentication ceremony. The BLE proximity requirement ensures that the phone must be physically near the laptop, preventing remote relay attacks.
From the CDN perspective, cross-device authentication does not change the network-level flow. The BLE communication happens locally between the user's devices. The laptop's browser still sends the standard WebAuthn API requests to the server through the CDN. The CDN does not need to handle any BLE-specific traffic or protocols. The only observable difference is a slightly longer round-trip time for the authentication ceremony because the user must physically interact with two devices.
Migration strategy: passwords to passkeys
Migrating an existing web application from password-based authentication to passkeys is a phased process that should not force users to abandon their current login method immediately. The recommended migration path follows three stages.
In the first stage, add passkey support alongside existing password authentication. After a successful password login, prompt the user to register a passkey. Store the passkey credential alongside the existing password hash. Users who register a passkey can use either method to log in. This stage is purely additive and carries no risk to existing users.
In the second stage, promote passkey authentication as the primary method. Display the passkey option first on the login page, with password login available as a secondary option. Track passkey adoption metrics: what percentage of active users have registered at least one passkey, and what percentage of login events use passkeys versus passwords. When passkey adoption reaches a sufficient threshold (typically 60 to 80 percent of active users), proceed to the third stage.
In the third stage, deprecate password authentication for accounts that have at least one registered passkey. Accounts without passkeys retain password access. Provide clear communication and a generous transition period before removing password support entirely. Some SaaS platforms may choose to retain password authentication indefinitely as a recovery mechanism for edge cases.
Infrastructure requirements for passkey migration
The migration adds new infrastructure requirements. The WebAuthn server component needs a credential store (database table or key-value store) that maps user accounts to one or more passkey credentials. Each credential record includes the credential ID, public key, signature counter, creation timestamp, last-used timestamp, and transport hints. The credential store must support efficient lookups by credential ID (for authentication) and by user ID (for listing a user's registered credentials).
The origin server must handle the increased request volume from WebAuthn ceremonies. Each login now requires two round trips (begin + complete) instead of one (password submission). The challenge generation and verification endpoints must be co-located with the credential store because they cannot be served from a CDN cache. The edge computing layer can offload some of this work by performing preliminary validation (checking that the request body is well-formed JSON with the expected fields) before forwarding to the origin, reducing the load on the authentication server from malformed or malicious requests.
Session management after successful passkey authentication follows the same patterns as password-based authentication. The origin server issues a session token (typically a signed JWT or an opaque session ID with server-side storage) that the browser includes in subsequent requests. The CDN edge can validate these session tokens at the edge using cached public keys, providing zero-trust verification without an origin round trip for every authenticated request. This combination of passkey authentication at the origin and token validation at the edge provides both strong initial authentication and efficient ongoing session verification.
Frequently asked questions
1. What is the difference between passkeys and traditional two-factor authentication?
Traditional two-factor authentication adds a second verification step (SMS code, TOTP token, or push notification) on top of a password. Passkeys replace both the password and the second factor entirely. A passkey uses public-key cryptography where the private key never leaves the authenticator device. The biometric or PIN unlock on the device serves as the user verification step, making passkeys inherently multi-factor: possession of the device plus a biometric or knowledge factor. Passkey authentication eliminates phishing risk because there is no shared secret to intercept.
2. Can passkeys work behind a CDN or reverse proxy?
Yes, but the CDN must forward WebAuthn challenge-response payloads without modification. The registration and authentication ceremonies use JSON payloads over standard HTTPS POST requests. CDN edge servers cache the static assets of the login page but must proxy the WebAuthn API endpoints directly to the origin. The CDN must preserve the Origin header and not modify the response body, as WebAuthn responses contain cryptographic signatures that any alteration invalidates. TLS termination at the CDN edge is acceptable because WebAuthn security relies on the origin binding in the credential, not transport-layer encryption alone.
3. What happens if a user loses their device with synced passkeys?
Synced passkeys are backed up to the platform vendor's cloud (Apple iCloud Keychain, Google Password Manager, or Microsoft account). If a user loses a single device, their passkeys remain available on any other device signed into the same platform account. If a user loses access to their entire platform account, they need the platform's account recovery process. Organizations should implement fallback authentication methods such as recovery codes, a secondary email verification flow, or a supervised in-person identity verification process.
4. Are passkeys vulnerable to man-in-the-middle attacks?
Passkeys are resistant to man-in-the-middle attacks by design. During registration, the authenticator binds the credential to the relying party's origin (the exact domain). During authentication, the authenticator includes the origin in the signed assertion. A phishing site on a different domain cannot obtain a valid signature because the authenticator refuses to use a credential bound to a different origin. This origin binding is enforced at the hardware or operating system level and cannot be bypassed by browser extensions or malicious scripts.
5. How do passkeys handle cross-device authentication?
Cross-device authentication uses the FIDO2 CTAP2 hybrid transport. When a user authenticates on a device without the passkey, the browser displays a QR code. The user scans this QR code with their phone (which holds the passkey), and the phone communicates with the browser over a Bluetooth Low Energy (BLE) proximity channel to complete the ceremony. The BLE channel ensures the authenticating device is physically nearby, preventing remote relay attacks. After initial pairing, subsequent cross-device authentications can use the established BLE link without scanning a QR code again.