Skip to content
authentication

FIDO2 Explained: CTAP2, WebAuthn, and Where Security Keys Still Win

Updated 2026-05-15 · 11 min read · By @guptadeepak

Key takeaways

  • FIDO2 is the umbrella spec: WebAuthn is the W3C browser-side API; CTAP2 is the FIDO Alliance protocol between browser and external authenticator.
  • Passkeys are FIDO2 credentials that sync across the user's devices via a platform cloud (iCloud, Google, Microsoft). FIDO2 without sync is the security-key model.
  • Attestation tells the relying party which authenticator was used. Most consumer flows do not request it; enterprise flows that require specific hardware do.
  • Platform authenticators (Touch ID, Face ID, Windows Hello) are the consumer default; roaming authenticators (YubiKey, Titan) win for high-assurance enterprise.
  • Account recovery is the unsolved problem. Passkey sync solves it for consumer; enterprise must plan a recovery path that does not undo the assurance.

What FIDO2 actually is

The three actors in any FIDO2 flow:

  • Relying Party (RP): the website or application that wants to authenticate the user. Calls navigator.credentials.create() to register a credential and navigator.credentials.get() to authenticate. The protocol details are covered in WebAuthn Explained.
  • Client / Browser: orchestrates the user-facing flow, talks to the authenticator over CTAP2 (or internally if the authenticator is built into the device).
  • Authenticator: holds the private key, performs the signing operation, and (sometimes) provides attestation. Either a platform authenticator (built into the device) or a roaming authenticator (external — security key over USB/NFC/Bluetooth).

CTAP2: the part most RPs never see

CTAP2 is the binary protocol the browser uses to talk to a roaming authenticator. The RP almost never deals with it directly — the browser handles the transport, and the WebAuthn API surfaces the result. CTAP2 is what makes a YubiKey work in Chrome the same way as in Safari, and what makes Bluetooth security keys discoverable across platforms.

CTAP2.1 added support for PIN-protected credentials (so a stolen key cannot be used without the PIN), client-side credential storage (the security key remembers its credentials, enabling username-less login), and enterprise attestation (a richer attestation format intended for managed enterprise deployments).

CTAP2.2, current in 2026, added hybrid transports (caBLE — Bluetooth proximity-based cross-device flows, used for cross-device passkey use) and refinements to attestation format negotiation.

Platform vs roaming authenticators

The choice that drives most deployment decisions:

  • Platform authenticators are built into the device: Touch ID on Mac, Face ID on iPhone, Windows Hello on Windows 10/11, Android biometric prompts. The private key lives in hardware-protected storage (Secure Enclave, TPM, StrongBox). The user authenticates with biometric or device PIN. Modern platforms also sync these credentials across the user's devices via the platform cloud — these are passkeys.
  • Roaming authenticators are external devices: YubiKey, Google Titan, Feitian, SoloKey. They connect over USB, NFC, or Bluetooth. Credentials are bound to the physical key; if the user loses the key, those credentials are gone.

For consumer applications, platform authenticators (and the passkey UX) are almost always the right default. The phishing-resistance is the same; the UX is better; recovery via platform sync is built in. For high-assurance enterprise — administrator consoles, code signing, key management for sensitive infrastructure — roaming authenticators with attestation pinned to a hardware allowlist are still the right tool. The credential lives on a piece of hardware your security team chose and provisioned; sync is the wrong property.

Attestation: what it proves and when to require it

Attestation is the authenticator's signed statement of "I am make X, model Y, AAGUID Z". The RP can use it to enforce that only approved authenticators are allowed.

Attestation formats:

  • none: no attestation. The credential is created, but the RP cannot tell what produced it. Default for most consumer flows; passkeys often use this because attestation would link credentials across RPs in unwanted ways.
  • packed: a compact attestation format supporting FIDO2 authenticators in general.
  • fido-u2f: legacy format from FIDO U2F. Still supported by older security keys.
  • tpm: attestation by a TPM (Windows Hello platform authenticator).
  • android-key, android-safetynet, apple: platform-specific attestations from Android and Apple.
  • enterprise: a CTAP 2.1+ format for managed enterprise authenticators that can identify the device uniquely.

When to require attestation: the relying party has a regulatory or compliance reason to enforce specific hardware (FIPS 140-2, Common Criteria EAL4+, NSA-approved, FedRAMP High). The flow asks for attestation: 'direct' on registration, parses the resulting attestation statement, and rejects credentials from AAGUIDs not on the allowlist.

When not to require attestation: most consumer flows. Demanding it filters out platform authenticators that ship attestation-free, fails on iCloud passkeys, and provides little value vs. the friction it causes.

The FIDO Metadata Service is the canonical source for AAGUID-to-device-metadata mapping. Enterprise deployments pull from it (or a mirror) and use the metadata to decide what to accept.

User verification: biometric, PIN, or presence

Each authenticator declares whether it performed user verification:

  • User Presence (UP): someone touched the key. Defeats malware-driven silent use, but does not bind the credential to the user identity.
  • User Verification (UV): the user proved who they are — biometric, device PIN, or authenticator PIN.

The RP requests user verification by setting userVerification: 'required' on the WebAuthn call. For a single-factor passwordless login, UV is required (the FIDO2 credential plus the biometric is the second factor). For a step-up MFA prompt on an already-authenticated session, UP may be enough.

Discoverable credentials and username-less login

A discoverable credential (formerly "resident key") is stored on the authenticator itself, not just by the RP. The benefit: the user can sign in without first entering a username. The flow:

  1. User clicks "Sign in with passkey".
  2. Browser asks the authenticator: "any credentials for this RP?"
  3. Authenticator shows the user a picker of accounts and asks for UV.
  4. User picks the right account; the authenticator returns the assertion with the credential ID and the user handle.
  5. RP looks up the user by the user handle and authenticates.

Discoverable credentials are what makes passkeys feel magical: tap the field, pick the account, done. For security keys, discoverable credentials require some on-key storage — most modern YubiKeys support several.

Account recovery: the hard problem

FIDO2 without sync is hostile to lost-key scenarios. A lost YubiKey, no backup registered, no fallback channel — the user is locked out. The patterns that work:

  1. Require two authenticators from registration. Best for high-assurance enterprise. Primary plus backup, both vetted hardware, both stored separately.
  2. Combine with passkeys for consumer. A passkey synced via iCloud / Google / Microsoft cloud is the recovery path — the credential travels with the user's platform account.
  3. Recovery codes. A printable, one-time-use string. Lower assurance than the FIDO2 credential, but defeats permanent lockout. Users mostly lose these too.
  4. Magic link to a vetted email. Drops assurance to whatever email security provides — fine for low-stakes consumer, wrong for admin access.
  5. In-person or video re-verification. For high-assurance accounts, force the user through identity proofing again. Operationally expensive; appropriate for crown-jewel access.

The recovery path is part of the security design, not an afterthought. A FIDO2 deployment whose recovery flow is "click 'I lost my key' and we email you a magic link" is, from an attacker's perspective, an email-based authentication scheme with extra steps.

When to require FIDO2 (and which kind)

The decision matrix that fits most deployments:

  • Consumer app, B2C: offer passkeys. Default platform authenticators. Optional roaming authenticator for users who want it. Account recovery via passkey sync + a magic link fallback for sync-account-loss edge cases.
  • B2B SaaS, end users: passkeys for primary, with the option to enroll a roaming authenticator. Sync within the user's personal cloud is fine for most workloads.
  • B2B SaaS, admin / privileged: require a roaming authenticator with attestation pinned to an enterprise-approved AAGUID allowlist. Two registered keys minimum. Recovery via in-band IT verification, not email.
  • Regulated workloads (FedRAMP High, NSA-approved, classified): roaming authenticators only, FIPS 140-2 attested, on the agency-approved list. PIN-protected. Sync disabled.

Implementation guidance

  1. Implement WebAuthn correctly first. FIDO2 in practice is a WebAuthn integration; the CTAP2 details are handled by the browser.
  2. Use a maintained library. simplewebauthn (TypeScript), py_webauthn (Python), webauthn4j (JVM), Yubico/java-webauthn-server (JVM).
  3. Pick your attestation policy up front. Consumer = none. Enterprise = direct, plus an allowlist of AAGUIDs from FIDO Metadata Service.
  4. Default platform authenticators for consumer flows. authenticatorSelection.authenticatorAttachment: 'platform' plus a UI affordance to enroll roaming authenticators as backup.
  5. Require user verification for primary login. userVerification: 'required'.
  6. Discoverable credentials by default for passkey-style flows. residentKey: 'preferred' or 'required'.
  7. Plan account recovery before launch. The hardest design question; do not let it slip to post-launch.
  8. Combine with passkeys and adaptive auth for the production posture. FIDO2 is the credential; the broader system is what defeats the broader threat model.

Related vendors

FAQ

What's the difference between FIDO2, WebAuthn, and passkeys?
FIDO2 is the umbrella project from the FIDO Alliance and W3C. It is made of two specs: WebAuthn (the W3C browser API the relying party calls) and CTAP2 (the protocol between the browser and an external authenticator like a YubiKey). A passkey is a specific kind of FIDO2 credential — one that syncs across the user's devices via a platform cloud. Non-syncing device-bound FIDO2 credentials still exist and are what security keys produce.
Do I need to require security keys or can I just use passkeys?
Depends on the threat model. For consumer apps, passkeys are almost always sufficient — they replace passwords, defeat phishing, and the sync solves account recovery. For high-assurance enterprise (admin consoles, code signing, regulated workloads), require roaming authenticators with attestation pinned to a hardware allowlist; sync is the wrong property when the credential needs to be locked to a vetted device.
What is attestation and when does it matter?
Attestation is a signed statement from the authenticator declaring its make and model. The relying party uses it to verify the credential was created by an approved device. Consumer flows usually skip attestation (passkeys often do not provide it, by design). Enterprise flows that require specific FIDO2 hardware (FIPS-certified, NSA-approved, etc.) request attestation and check the resulting AAGUID against an allowlist.
Can a user have multiple FIDO2 credentials for one account?
Yes, and they should. The recovery story for non-syncing credentials depends on the user having a second authenticator registered. Best practice for accounts that require security keys is to require two from the start — primary and backup — so losing one does not lock the user out.
What happens if a user loses their YubiKey?
If they had a second authenticator registered, they log in with the backup and re-register a replacement. If they did not, they go through your account recovery flow — which must be carefully designed to not undo the assurance the YubiKey provided. Recovery via email magic link, for instance, drops the assurance level back to whatever email security provides.

Sources

  • WebAuthn Level 3 (W3C, 2024)
  • CTAP 2.2 (FIDO Alliance)
  • FIDO Metadata Service (FIDO Alliance)
  • NIST SP 800-63B-4 (AAL2 / AAL3 authenticator requirements)
Last reviewed 2026-05-15.