Scope
This guide covers the technical fundamentals, implementation requirements, and operational considerations for deploying passkey authentication in enterprise environments. It's designed for IAM architects and security engineers evaluating or implementing FIDO2 passkey systems as a replacement for password-based authentication.
You'll find insights on cryptographic primitives, protocol requirements, integration patterns, and common deployment mistakes. Vendor comparisons or specific product recommendations are not included.
Key Concepts and Definitions
Passkey: A FIDO2 credential with a private key stored on the user's device and a public key registered with your application. The private key never leaves the device.
Relying Party (RP): Your application or service that validates authentication assertions. You register the user's public key and verify signed challenges.
Authenticator: The device or platform component that stores the private key and performs cryptographic operations. This could be a phone's secure enclave, a laptop's TPM, or a hardware security key.
WebAuthn: The browser API that implements FIDO2 authentication. It manages communication between your web application and the authenticator.
Phishing-Resistant Authentication: Authentication that binds the credential to a specific origin. Passkeys include the domain in the signed assertion, preventing use on phishing sites.
Attestation: The process where an authenticator proves its authenticity to the relying party during registration. You can require specific authenticator types through attestation policies.
Requirements Breakdown
Protocol Requirements
Your implementation must support the WebAuthn Level 2 specification at minimum. Key parameters include:
Registration ceremony:
- Generate a cryptographic challenge (minimum 16 bytes of entropy).
- Specify
publicKey.rp.idmatching your domain. - Set
publicKey.user.idto a stable, non-PII identifier (not an email address). - Define acceptable authenticator types via
publicKey.authenticatorSelection. - Request attestation if you need to verify authenticator models.
Authentication ceremony:
- Generate a fresh challenge for each attempt.
- Verify the signature using the stored public key.
- Ensure
response.clientDataJSON.originmatches your expected domain. - Check the signature counter to detect cloned authenticators.
Server-Side Storage
Store these fields per user:
- Credential ID (unique identifier for the passkey).
- Public key (in COSE format).
- Signature counter (increments with each use).
- Authenticator metadata (optional: AAGUID, attestation data).
- Creation and last-used timestamps.
Don't use the credential ID as the primary key. Users can register multiple passkeys, so you'll need to look up all credentials for a user during authentication.
Client Integration
Your login flow needs two new endpoints:
POST /auth/passkey/begin, returns a challenge and credential options.POST /auth/passkey/verify, validates the signed assertion.
The browser calls navigator.credentials.create() for registration and navigator.credentials.get() for authentication. Ensure your system handles both flows when WebAuthn isn't available.
Implementation Guidance
Migration Strategy
Avoid a sudden switch. Run passkeys alongside existing authentication for 6-12 months:
Phase 1: Opt-in enrollment
Add a "Register a passkey" option in account settings. Let early adopters test the flow without risking lockouts. Monitor enrollment rates and support tickets.
Phase 2: Prompted enrollment
After a successful password login, prompt users to register a passkey. Make it skippable but persistent. Track registration completion rates.
Phase 3: Passkey-first login
Reorder your login UI to offer passkey authentication before the password field. Users without passkeys can still click "Use password instead."
Phase 4: Password deprecation
Once passkey adoption crosses your threshold (typically 70-80%), begin retiring passwords for enrolled users. Keep a recovery mechanism for device loss.
Handling Multiple Devices
Users expect to authenticate from multiple devices. You have two options:
Platform authenticators: Each device generates its own passkey. The user registers separate credentials for each device, which can be cumbersome.
Synced passkeys: The user's platform (iCloud Keychain, Google Password Manager) syncs the private key across devices. This is user-friendly but relies on the platform provider's sync security.
Most enterprises will support both. Allow users to register multiple passkeys and label them ("Work laptop", "iPhone").
Backup and Recovery
Ensure a recovery path for lost devices or platform switches:
- Require registration of multiple passkeys during setup (primary + backup).
- Offer account recovery via email or SMS with a time-delayed unlock.
- Integrate with your existing identity verification process (support desk, manager approval).
Don't make the recovery path weaker than the primary authentication.
Common Pitfalls
Pitfall 1: Treating the credential ID as a secret
The credential ID is public information. It's safe to send in the clear. The private key is the secret and never leaves the authenticator.
Pitfall 2: Ignoring the signature counter
A decreasing counter indicates a cloned authenticator. Lock the account and force re-registration. Many skip this check, missing cloning attacks.
Pitfall 3: Weak challenge generation
Using Math.random() or a timestamp makes the protocol vulnerable to replay attacks. Use a cryptographically secure random number generator with at least 128 bits of entropy.
Pitfall 4: Not validating the origin
Always verify that clientDataJSON.origin matches your expected domain. Skipping this check allows credential use on phishing sites.
Pitfall 5: Assuming universal support
WebAuthn isn't available on all browsers and devices. Provide a fallback authentication method and clear error messages when passkeys aren't supported.
Pitfall 6: Breaking existing sessions
When adding passkey support, don't invalidate current sessions. Let users try passkeys on their next login, not mid-session.
Quick Reference
| Requirement | Specification | Implementation Note |
|---|---|---|
| Challenge size | ≥16 bytes | Use 32 bytes for margin |
| Challenge lifetime | 2-5 minutes | Reject after timeout |
| Relying Party ID | Must match domain | Can be parent domain |
| User ID format | Opaque byte array | Don't use email |
| Credential storage | Per-user array | Support multiple passkeys |
| Signature verification | COSE algorithm | Typically ES256 or RS256 |
| Counter handling | Monotonically increasing | Lock account if it decreases |
| Origin validation | Exact match required | Check during verification |
| Attestation | Optional | Required for restricted authenticators |
| User verification | Platform-dependent | Biometric or PIN |
FIDO2 Certification
If you're building a new relying party implementation, consider FIDO Alliance certification. It's not mandatory, but it validates that your implementation handles edge cases in the WebAuthn specification.
Browser Compatibility
Check navigator.credentials availability before rendering the passkey UI. As of this writing, WebAuthn is supported in Chrome 67+, Firefox 60+, Safari 13+, and Edge 18+. Mobile support varies by platform and OS version.




