From 59830e19c80cd1fefed1f012fde00b1454219e72 Mon Sep 17 00:00:00 2001 From: Brad Stein Date: Sun, 4 Jan 2026 08:21:28 -0300 Subject: [PATCH] portal: stop forcing MFA on first login --- backend/atlas_portal/provisioning.py | 10 +++++- .../atlas_portal/routes/access_requests.py | 32 +++++++++---------- frontend/src/views/OnboardingView.vue | 25 ++------------- 3 files changed, 26 insertions(+), 41 deletions(-) diff --git a/backend/atlas_portal/provisioning.py b/backend/atlas_portal/provisioning.py index 80af303..1190748 100644 --- a/backend/atlas_portal/provisioning.py +++ b/backend/atlas_portal/provisioning.py @@ -204,7 +204,10 @@ def provision_access_request(request_code: str) -> ProvisionResult: raise RuntimeError("email is already associated with an existing Atlas account") # Always enforce email verification in Keycloak itself (even if the portal # already verified an external email before approval). - required_actions = ["UPDATE_PASSWORD", "VERIFY_EMAIL", "CONFIGURE_TOTP"] + # Do not force MFA enrollment during initial login: some users prefer to + # enable MFA later and some clients are too friction-heavy when MFA is + # mandatory for every service. + required_actions = ["UPDATE_PASSWORD", "VERIFY_EMAIL"] payload = { "username": username, "enabled": True, @@ -222,6 +225,11 @@ def provision_access_request(request_code: str) -> ProvisionResult: try: full = admin_client().get_user(user_id) attrs = full.get("attributes") or {} + actions = full.get("requiredActions") + if isinstance(actions, list) and "CONFIGURE_TOTP" in actions: + # Backfill earlier accounts created when we forced MFA enrollment. + new_actions = [a for a in actions if a != "CONFIGURE_TOTP"] + admin_client().update_user(user_id, {"requiredActions": new_actions}) mailu_from_attr: str | None = None if isinstance(attrs, dict): raw_mailu = attrs.get(MAILU_EMAIL_ATTR) diff --git a/backend/atlas_portal/routes/access_requests.py b/backend/atlas_portal/routes/access_requests.py index 015a4d0..076b28e 100644 --- a/backend/atlas_portal/routes/access_requests.py +++ b/backend/atlas_portal/routes/access_requests.py @@ -58,14 +58,12 @@ def _verify_url(request_code: str, token: str) -> str: ONBOARDING_STEPS: tuple[str, ...] = ( "keycloak_password_changed", - "keycloak_mfa_configured", "vaultwarden_master_password", "element_recovery_key", "element_recovery_key_stored", ) -KEYCLOAK_MANAGED_STEPS: set[str] = {"keycloak_password_changed", "keycloak_mfa_configured"} -KEYCLOAK_OTP_CRED_TYPES: set[str] = {"otp", "totp"} +KEYCLOAK_MANAGED_STEPS: set[str] = {"keycloak_password_changed"} def _normalize_status(status: str) -> str: @@ -109,25 +107,25 @@ def _auto_completed_keycloak_steps(username: str) -> set[str]: actions = full.get("requiredActions") required_actions: set[str] = set() + actions_list: list[str] = [] if isinstance(actions, list): - required_actions = {a for a in actions if isinstance(a, str)} + actions_list = [a for a in actions if isinstance(a, str)] + required_actions = set(actions_list) if "UPDATE_PASSWORD" not in required_actions: completed.add("keycloak_password_changed") - otp_present = False - try: - creds = admin_client().get_user_credentials(user_id) - for cred in creds: - ctype = cred.get("type") if isinstance(cred, dict) else None - if isinstance(ctype, str) and ctype.lower() in KEYCLOAK_OTP_CRED_TYPES: - otp_present = True - break - except Exception: - otp_present = False - - if otp_present or "CONFIGURE_TOTP" not in required_actions: - completed.add("keycloak_mfa_configured") + # Backfill: earlier accounts were created with CONFIGURE_TOTP as a required action, + # which forces users to enroll MFA at first login. We no longer require that, so + # remove it if present. + if "CONFIGURE_TOTP" in required_actions: + try: + admin_client().update_user( + user_id, + {"requiredActions": [a for a in actions_list if a != "CONFIGURE_TOTP"]}, + ) + except Exception: + pass except Exception: return set() diff --git a/frontend/src/views/OnboardingView.vue b/frontend/src/views/OnboardingView.vue index 7c9339a..5aeb678 100644 --- a/frontend/src/views/OnboardingView.vue +++ b/frontend/src/views/OnboardingView.vue @@ -81,7 +81,7 @@

- Some steps are verified automatically from Keycloak (password + MFA). Others can't be verified yet — mark them complete once you're done. + Some steps are verified automatically from Keycloak (password). Others can't be verified yet — mark them complete once you're done.

@@ -131,27 +131,6 @@

-
  • - -

    - Add a TOTP authenticator (2FA) in Keycloak: - account console. -

    -
  • -