The confusing failure: YubiKey registered in Chrome, login fails in Safari
A common FIDO2 security keys interoperability issue: you create a credential in Chrome, everything works, then Safari on the same machine can’t use that “same” YubiKey—often with no PIN prompt and basically no actionable error.
The usual root cause is WebAuthn credProtect (a.k.a. credentialProtectionPolicy, CTAP 2.1). Chrome silently hardens discoverable credentials on roaming keys in ways Safari can’t reliably satisfy.
The trigger combo: discoverable credentials + UV="preferred"
This mainly hits RPs that register/login with:
- residentKey: "required" (aka discoverable credentials / resident key)
- userVerification: "preferred" (chosen to avoid “hard fail” edge cases at scale)
With that combo, Chromium may escalate the credential to credProtect Level 3 (UV required at the authenticator), even if you didn’t explicitly request it.
CTAP 2.1 credProtect levels (why Level 3 is special)
credProtect controls whether a credential can be discovered/used without user verification:
- Level 1 (UV optional): max compatibility.
- Level 2 (UV optional with credential ID list): hides resident creds unless you provide allowCredentials.
- Level 3 (UV required): key refuses assertions unless UV succeeds (PIN/biometric).
Level 3 is great security-wise, but it becomes an interop footgun when browsers don’t implement the same CTAP flows.
Why Safari is the odd one out (roaming authenticator limitations)
Safari’s WebAuthn stack is optimized around platform passkeys (Secure Enclave ≈ “always UV”). For roaming authenticators, Safari (as of early 2026 per the article):
- doesn’t reliably send/handle credentialProtectionPolicy for external keys
- often won’t prompt to set up a PIN when UV is only preferred
- may fail the UV/PIN handshake a Level 3 credential requires
Result: a credential that Chrome created with Level 3 can look like “no credential found” in Safari.
Practical signal: Chrome-to-Safari breakage is mostly Level 3
The article’s testing summary is basically:
- Chrome + UV="required" → tends to produce credProtect Level 2 → works in Safari/Firefox ✅
- Chrome + UV="preferred" (with RK required) → escalates to Level 3 → fails in Safari ❌
That “counterintuitive” matrix is the heart of the bug reports.
Firefox 139+ is catching up (but behaves differently)
Firefox 139 added credProtect support (authenticator-rs). It’s closer to spec parity now, and generally sticks more to what the RP explicitly requests (less implicit escalation than Chrome).
What to do as an RP (2 viable strategies)
-
If security keys might be involved: set userVerification: "required" 🔐
- avoids Chrome’s Level 3 escalation
- aligns PIN prompts across browsers
- yields credentials that interop better
- If you must keep UV="preferred" at scale:
- check UV flag server-side after registration
- use getClientExtensionResults() to see whether credProtect applied
- downgrade trust / require extra factor (Google-style) when UV wasn’t performed
Final note
credProtect itself isn’t “bad”—the pain comes from inconsistent browser behavior (especially Safari + roaming authenticators). If you’re seeing the “Safari does nothing” bug: look at credProtect Level 3 + UV preferred vs required first. 🧪🔑
Find out more on the full write-up: https://www.corbado.com/blog/webauthn-credprotect-security-keys
Top comments (0)