feat(auth): prefer rather than require passkey user verification
Chart Release / chart (push) Successful in 20s
Server Deploy / deploy (push) Successful in 2m59s

Requiring user verification made password managers such as NordPass ask
for their master password on every passkey use. Every ceremony now asks
for it as preferred and no longer rejects a result without it.

This is a deliberate trade-off: a passkey used without verification is
possession-only, so passwordless sign-in and step-up rest on the device or
vault being unlocked. The spec records the decision.
This commit is contained in:
2026-09-16 15:20:31 +00:00
parent 934501f4ec
commit 217e2dc5a9
4 changed files with 18 additions and 20 deletions
@@ -17,7 +17,7 @@ In:
- TOTP as a second factor, with 10 single-use recovery codes.
- WebAuthn passkeys, both as a second factor after a password and as
passwordless sign-in (discoverable credentials, user verification required).
passwordless sign-in (discoverable credentials, user verification preferred).
- An owner setting, `require_mfa`, that forces enrolment for password users.
- Owner/admin reset of another member's MFA.
- Step-up re-authentication before three sensitive actions: secret reveal,
@@ -174,8 +174,11 @@ at their 24h TTL and the next sign-in enforces enrolment.
`{instance_id, credential_id}`, verifies the assertion including the UV flag,
and mints the session with `amr: ["webauthn"]`.
A user-verified passkey is possession plus biometric or PIN, so it satisfies
`require_mfa` on its own.
User verification is preferred, not required. Requiring it made password
managers such as NordPass prompt for their master password on every use, so it
was relaxed on 2026-09-16 at the product owner's decision. A passkey used
without verification is possession-only; passwordless sign-in and step-up then
rest on the device or vault being unlocked, and still satisfy `require_mfa`.
The discoverable lookup is scoped by `instance_id` from the host, never by the
credential alone - the same rule that makes `users` lookups instance-scoped.