Passkeys replace passwords with public-key cryptography. Your server (the relying party) never stores a shared secret; it stores a public key and verifies signatures produced by an authenticator the user controls. If the relying party skips origin verification, mishandles challenges, or stores credentials without the right metadata, you lose the phishing resistance that makes passkeys worth adopting. This post focuses on the RP-side architecture: ceremony verification, credential storage, and the trust boundaries between browser, authenticator, and your server.
System description
A relying party issues random challenges, verifies signed responses from authenticators, and stores credential public keys. Two ceremonies define the protocol: registration (create a credential) and authentication (prove you hold it). The browser mediates both ceremonies, enforcing origin binding before the authenticator ever sees the request.

Architecture choice
There are two models for authenticator attestation, and the choice affects what you can enforce about credential provenance.
Accept all authenticators (no attestation verification)
Accept attestation: "none" or "indirect". Register any credential the browser presents, regardless of which authenticator created it.
Use this when:
You're building a consumer-facing application
You want maximum compatibility across devices and passkey providers (iCloud Keychain, Google Password Manager, 1Password, hardware keys)
You don't need to enforce hardware-specific security policies
Main risks: You cannot distinguish a hardware-bound key from a software-synced key by attestation alone, though the BE (Backup Eligible) and BS (Backup State) flags still provide that signal. You cannot block known-vulnerable authenticator models.
Verify attestation against FIDO Metadata Service
Request attestation: "direct". Verify the attestation statement's certificate chain against root certificates from the FIDO Metadata Service (MDS). Enforce an allowlist of AAGUIDs (authenticator model identifiers).
Use this when:
Enterprise policy requires specific hardware authenticators (FIPS-certified, company-provisioned)
You need to block authenticator models with known vulnerabilities
Regulatory requirements mandate authenticator-level assurance
Trade-off: You must maintain a trust store of attestation root certificates, consume MDS updates, and implement format-specific verification logic for each attestation type (packed, tpm, android-key, apple, fido-u2f). Requiring attestation also excludes passkey providers that return none. Use a maintained WebAuthn server library for attestation verification. Do not implement format-specific parsing manually.
Common middle ground: Accept all authenticators by default. Check the BE flag to distinguish synced from device-bound credentials. If your policy requires device-bound keys for specific roles or actions, enforce that at registration time without requiring full attestation verification.
Golden path
Build this first. Then relax constraints only if you have a specific reason:
Generate session-bound challenge → browser mediates ceremony → authenticator signs response → RP verifies ceremony → store credential with metadata → issue sessionEach step is a verification gate. A failure at any point rejects the ceremony.
Generate session-bound challenge: 16+ bytes of randomness, stored server-side with a 60-120s TTL
Browser mediates ceremony: The browser enforces RP ID matching against the page origin before the authenticator is involved; your server validates the result afterward
Authenticator signs response: Signs over
authenticatorData || SHA-256(clientDataJSON), binding challenge and origin into the signatureRP verifies ceremony: Validates origin, challenge,
rpIdHash, flags (UP= User Present,UV= User Verified), and signature. For discoverable flows, confirmscredentialIdis bound to theuserHandleStore credential with metadata: Persist
credentialId, public key,signCount,transports,BE,BS, andaaguidalongside the user recordIssue session: The ceremony proves identity at a point in time; the session token carries it forward
Minimal system context
Challenge store (session state): Server-side storage (HTTP session, Redis, signed cookie) that maps a session to a pending challenge. Challenges are single-use; consumed after verification or expired after TTL
Ceremony verifier (control plane): Parses
clientDataJSONandauthenticatorData, enforces origin and RP ID checks, verifies cryptographic signaturesCredential store (data plane): Persistent storage for credential records. Each record maps a
credentialIdto a user, a public key, a sign count, transport hints, andBE/BSflagsSession manager (identity): Issues authenticated sessions after successful ceremonies. Separate from the challenge store
Security properties of WebAuthn ceremonies
The ceremony binds:
The credential to a specific RP ID (via
rpIdHashinauthenticatorData)The ceremony to a specific origin (via
origininclientDataJSON)The response to a specific challenge (via
challengeinclientDataJSON, covered by the signature)User presence and optionally user verification (via
UPandUVflags inauthenticatorData)
It does not bind:
The resulting session token to the ceremony (the session is a bearer token after issuance)
The credential to a specific device, if the credential is sync-eligible
BE=1)The RP ID to a single origin (multiple subdomains can share an RP ID if it's set to the registrable domain)
The origin check in clientDataJSON is the primary anti-phishing mechanism. The authenticator never sees the origin; it works with rpIdHash. The browser enforces origin-to-RP-ID matching before the ceremony begins, and the RP verifies the origin after. Both checks must pass.
Threat model
Baseline assumptions
Browsers are trusted to enforce origin and RP ID matching correctly. Browser-level compromises (extensions, malware) are out of scope
The authenticator protects private keys. Authenticator firmware vulnerabilities are out of scope for this model
TLS is in place. The RP is served over HTTPS. Network-level MITM is not modeled
Standard infra controls (database AuthN, input validation, rate limiting) are assumed. This model focuses on the WebAuthn ceremony and credential management logic
A note on risk: you won’t fix everything
This table isn’t a checklist where every row must be fully eliminated. Focus on preventing the worst failures and limiting blast radius. In practice: ship prevention for the High rows first, then add monitoring and response for what you can’t realistically prevent.
Phase 1: Ceremony integrity
Focus: Preventing replay, phishing, and verification bypasses
Asset | Threat | Baseline Controls | Mitigation Options | Risk |
|---|---|---|---|---|
Ceremony | Challenge replay: Attacker captures a signed WebAuthn response and replays it against the RP. If challenges aren't session-bound and single-use, the replayed response passes verification | Server-generated challenge | 1. Session binding: Store challenges server-side, tied to the authenticated or anonymous session that initiated the ceremony 2. Single-use: Delete the challenge after successful verification or TTL expiry 3. Short TTL: Expire unused challenges within 60-120 seconds | High |
Origin trust | Sibling-domain phishing: RP sets | RP ID binding | 1. Strict origin check: Verify 2. Subdomain hygiene: Audit all subdomains under your RP ID domain. Unused subdomains are takeover targets 3. Narrow RP ID: If your app runs on a single subdomain, set | Medium |
User verification | UV bypass: RP requests | Flag in | 1. Flag enforcement: If you set 2. Registration policy: Require UV at registration so the authenticator sets up a local verification method (PIN, biometric) | Medium |
Phase 2: Credential management
Focus: Preventing enumeration, confusion, and stale credential risks
Asset | Threat | Baseline Controls | Mitigation Options | Risk |
|---|---|---|---|---|
User privacy | Credential enumeration: RP returns | Auth required for lookup | 1. Discoverable credentials: Use the passkey flow where 2. Conditional UI: Use 3. Dummy responses: For non-discoverable fallback flows, return a plausible-looking dummy challenge for nonexistent users | Low |
Credential integrity | Credential confusion: Attacker registers a credential ID that already belongs to another user. If the RP doesn't enforce uniqueness, authentication becomes ambiguous | Credential lookup by ID | 1. Uniqueness check: Reject registration if the 2. User binding: Always verify that the credential's associated | Medium |
Cloned authenticator | Sign count regression: For device-bound credentials ( |
| 1. Conditional enforcement: For 2. Skip for synced: For 3. Alert: Log sign count anomalies for investigation | Low |
Credential metadata | Missing transport hints: RP doesn't store | None | 1. Store transports: Call 2. Pass hints: Include stored transports in | Low |
Phase 3: Post-ceremony session
Focus: Preventing session hijacking after a successful passkey ceremony
Asset | Threat | Baseline Controls | Mitigation Options | Risk |
|---|---|---|---|---|
Authenticated session | Session theft: The passkey ceremony proves identity at one moment. The resulting session token is a bearer token. If stolen (XSS, malware, network interception on a misconfigured setup), the attacker inherits the session without ever touching the authenticator | Standard session management | 1. Short-lived sessions: Reduce the window during which a stolen token is useful 2. Step-up auth: Require a fresh passkey ceremony for sensitive operations (password change, payment, admin actions) 3. Binding signals: Tie the session to client properties (IP range, TLS fingerprint) where feasible, accepting the false-positive cost for mobile users | Medium |
Account | Credential stuffing the ceremony endpoint: Attacker floods the authentication endpoint with ceremony initiation requests to exhaust server-side challenge storage or cause resource exhaustion | Rate limiting | 1. Per-IP rate limits: Throttle ceremony initiation requests 2. Challenge storage limits: Cap the number of pending challenges per session or per IP 3. Proof of work: For anonymous ceremony initiation, consider lightweight client puzzles | Low |
Verification checklist
Ceremony verification
origininclientDataJSONis checked against an explicit allowlist of expected origins using exact string equality (not regex or suffix matching)challengeinclientDataJSONmatches the server-side challenge for this specific sessionChallenges are single-use and expire within 120 seconds
rpIdHashinauthenticatorDataequals SHA-256 of the configured RP IDtypeinclientDataJSONis"webauthn.create"for registration and"webauthn.get"for authenticationFor discoverable credential flows,
userHandlefrom the assertion identifies the user, andcredentialIdis confirmed to be bound to that userIf the challenge store is unreachable, ceremony initiation fails closed (returns error), not open (skips challenge binding)
Flag enforcement
UP=1is verified on every ceremonyUV=1is verified whenuserVerification: "required"was requestedBEandBSflags are stored per credential and available for policy decisions
Credential storage
Each credential record stores:
credentialId, public key,signCount,transports,aaguid,BE,BScredentialIdis unique across all users (registration rejects duplicates)Sign count is verified for
BE=0credentials;signCount=0is accepted forBE=1credentials
Enumeration resistance
Authentication endpoints return identical response timing and structure for existing and non-existing users
The primary authentication flow uses discoverable credentials (empty
allowCredentials)
Session management
Sensitive operations require step-up authentication (fresh passkey ceremony), not just an existing session
Ceremony initiation endpoints are rate-limited per IP
Environment isolation
RP ID is environment-specific; credentials registered in dev/staging cannot authenticate in production
Attestation (if verifying)
Attestation root certificates are sourced from FIDO Metadata Service and updated regularly
Only AAGUIDs on the allowlist are accepted during registration
Credentials with unknown or revoked attestation are rejected
Implementation & Review
The full threat model matrix, architectural diagrams, and a printable verification checklist for this pattern are available in the Secure Patterns repository. Use these artifacts to guide your design reviews and internal audits.
