fix: always offer MFA+passkey enrollment, separate availability from enforcement
All checks were successful
CI / build (push) Successful in 2m19s
CI / docker (push) Successful in 1m43s

Two fundamental fixes:

- user.missing_mfa now triggers MfaEnrollmentError (enroll UI) instead
  of MfaRequiredError (verify UI). Users without MFA were shown a TOTP
  code prompt they couldn't fill.
- Logto MFA factors always set to [Totp, WebAuthn, BackupCode] with
  UserControlled policy on startup. Availability is always-on for all
  users. The vendor auth policy controls enforcement (via
  MfaEnforcementFilter), not what Logto offers during sign-in.
- Removed syncMfaConfigToLogto from VendorAuthPolicyController — vendor
  policy changes no longer modify Logto's sign-in experience.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-27 18:59:21 +02:00
parent 67ec409383
commit cba420fbeb
3 changed files with 11 additions and 71 deletions

View File

@@ -99,13 +99,13 @@ export async function signIn(identifier: string, password: string): Promise<stri
const result = await trySubmit();
if (result.ok) return result.redirectTo;
// MFA already enrolled — user must verify (show TOTP input)
if (result.code === 'user.missing_mfa' || result.code === 'session.mfa.require_mfa_verification') {
// MFA already enrolled — user must verify (show TOTP/passkey input)
if (result.code === 'session.mfa.require_mfa_verification') {
throw new MfaRequiredError();
}
// MFA not enrolled — offer enrollment (passkey / TOTP)
if (result.status === 422 && result.code.includes('mfa')) {
if (result.code === 'user.missing_mfa' || (result.status === 422 && result.code.includes('mfa'))) {
throw new MfaEnrollmentError();
}