Passkey
// Implement WebAuthn passkeys avoiding critical security and compatibility pitfalls.
$ git log --oneline --stat
stars:1,933
forks:367
updated:March 4, 2026
SKILL.mdreadonly
SKILL.md Frontmatter
namePasskey
descriptionImplement WebAuthn passkeys avoiding critical security and compatibility pitfalls.
metadata[object Object]
Security-Critical Rules
- Challenge must be unique per ceremony — reused challenges enable replay attacks
- Origin validation is mandatory — missing check allows phishing from similar domains
- Store and verify sign count — detects cloned authenticators when count doesn't increment
- Never implement CBOR parsing manually — use established libraries, crypto is hard
Server Implementation
- Use battle-tested libraries — SimpleWebAuthn (JS), py_webauthn (Python), webauthn-rs (Rust)
- Challenges expire quickly — 60-120 seconds max, store server-side
- Store credential ID as base64 — binary data, needs encoding for database
- Store public key in COSE format — libraries handle this, don't transform it
Credential Storage Requirements
- Credential ID — unique identifier, used in allowCredentials
- Public key — COSE format, for signature verification
- Sign count — integer, increment check detects cloning
- Transports hint — helps browser suggest correct authenticator
Registration Traps
userVerification: "required"enforces biometric/PIN — "preferred" may skip verification- Attestation usually unnecessary — requiring it reduces device compatibility
- Allow multiple passkeys per account — users have multiple devices
- Resident key capability varies — don't assume all authenticators support discoverable credentials
Authentication Traps
- Empty allowCredentials enables discoverable credentials — but not all passkeys are discoverable
- Timeout too short frustrates users — 120 seconds minimum for cross-device flows
- Cross-device auth (QR code) adds latency — don't timeout during Bluetooth handshake
User Experience
- Provide password fallback — not all users have passkey-capable devices
- Conditional UI (
mediation: "conditional") for autocomplete — passkeys appear in username field - Clear messaging on registration — users don't understand "security key" terminology
- Account recovery path required — hardware loss shouldn't lock out account forever
Platform Sync Behavior
- Apple iCloud Keychain syncs across Apple devices — but not to Android/Windows
- Google Password Manager syncs Android + Chrome — but not to Apple devices
- Windows Hello is TPM-backed, local by default — doesn't sync
- 1Password/Bitwarden provide cross-platform sync — broadest compatibility option
Testing
- Chrome DevTools > Application > WebAuthn — simulate authenticators without hardware
- Virtual authenticators in CI — no physical keys needed for automated tests
- Test both resident and non-resident credentials — different flows
- Cross-browser testing essential — Safari, Chrome, Firefox implementations vary