fix: passkeys work independently of MFA mode
All checks were successful
CI / build (push) Successful in 2m15s
CI / docker (push) Successful in 1m1s

When MFA mode is off but passkeys are enabled, WebAuthn + BackupCode
factors are still synced to Logto. Previously, MFA off cleared all
factors including WebAuthn, so passkey enrollment was never offered.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-27 18:45:30 +02:00
parent 18e6f32f90
commit 3384510f3c
2 changed files with 17 additions and 11 deletions

View File

@@ -40,14 +40,17 @@ public class LogtoStartupConfig {
var policy = authPolicyRepository.getPolicy(); var policy = authPolicyRepository.getPolicy();
String mfaMode = policy.getMfaMode(); String mfaMode = policy.getMfaMode();
boolean mfaEnabled = !"off".equals(mfaMode); boolean mfaEnabled = !"off".equals(mfaMode);
boolean passkeyEnabled = policy.isPasskeyEnabled();
if (!mfaEnabled) { List<String> factors = new ArrayList<>();
logtoClient.updateSignInExperience(Map.of( if (mfaEnabled) {
"mfa", Map.of("factors", List.of(), "policy", "UserControlled"))); factors.add("Totp");
return; }
if (mfaEnabled || passkeyEnabled) {
factors.add("WebAuthn");
factors.add("BackupCode");
} }
List<String> factors = new ArrayList<>(List.of("Totp", "WebAuthn", "BackupCode"));
String logtoPolicy = "required".equals(mfaMode) ? "Mandatory" : "UserControlled"; String logtoPolicy = "required".equals(mfaMode) ? "Mandatory" : "UserControlled";
logtoClient.updateSignInExperience(Map.of( logtoClient.updateSignInExperience(Map.of(

View File

@@ -73,14 +73,17 @@ public class VendorAuthPolicyController {
try { try {
String mfaMode = policy.getMfaMode(); String mfaMode = policy.getMfaMode();
boolean mfaEnabled = !"off".equals(mfaMode); boolean mfaEnabled = !"off".equals(mfaMode);
boolean passkeyEnabled = policy.isPasskeyEnabled();
if (!mfaEnabled) { List<String> factors = new ArrayList<>();
logtoClient.updateSignInExperience(Map.of( if (mfaEnabled) {
"mfa", Map.of("factors", List.of(), "policy", "UserControlled"))); factors.add("Totp");
return; }
// Passkeys are always available when enabled, regardless of MFA mode
if (mfaEnabled || passkeyEnabled) {
factors.add("WebAuthn");
factors.add("BackupCode");
} }
List<String> factors = new ArrayList<>(List.of("Totp", "WebAuthn", "BackupCode"));
String logtoPolicy = "required".equals(mfaMode) ? "Mandatory" : "UserControlled"; String logtoPolicy = "required".equals(mfaMode) ? "Mandatory" : "UserControlled";