mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
# Which Problems Are Solved
Users with a passkey plus an additional configured second factor (TOTP /
OTP Email / OTP SMS) get stuck on the passkey verification page: the
WebAuthn ceremony succeeds, but the continue button just spins and the
user is redirected back to `/passkey` indefinitely. Re-registering the
passkey or switching to a private window does not help.
Since the MFA hardening of `isSessionValid` (56f4798), a session is only
considered valid if one of the user's *configured* MFA methods (TOTP,
OTP Email, OTP SMS, U2F) was verified within the session. A passkey
login sets `factors.webAuthN.verifiedAt` with `userVerified: true`, but
only the U2F method reuses that factor — so a passkey session for a user
whose second factor is TOTP or OTP is deemed invalid at flow completion.
This contradicts the login flow itself: `checkMFAFactors` intentionally
never prompts for a second factor after a passkey login ("escape further
checks if user has authenticated with passkey"). The result is a loop:
1. Passkey is verified on `/passkey` → `sendPasskey` →
`completeAuthFlow` → `loginWithOIDCAndSession`
2. `isSessionValid` returns `false` because the configured TOTP/OTP
factor was never checked in this session
3. The re-authentication branch calls `sendLoginname`, which resolves
the user's preferred method (passkey) and returns a redirect to
`/passkey` — back to step 1, with no way forward
# How the Problems Are Solved
Treat a user-verified passkey authentication as fulfilling the MFA
requirement in `isSessionValid`, consistent with the existing passkey
escape in `checkMFAFactors`. A passkey with user verification is
inherently multi-factor (possession + biometrics/PIN).
- `isSessionValid` now derives `hasAuthenticatedWithPasskey` from
`factors.webAuthN.verifiedAt && factors.webAuthN.userVerified` and
accepts it alongside the configured-factor checks (`totpValid ||
otpEmailValid || otpSmsValid || u2fValid`).
- A presence-only WebAuthn assertion (`userVerified: false`, i.e. a
U2F-style second-factor check) does **not** count, so password-based
sessions still require their configured second factor — the original
security fix remains intact.
- Adds regression tests: a user-verified passkey session with a
configured-but-unverified TOTP factor is valid; a presence-only WebAuthn
session with an unverified TOTP factor remains invalid.