Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion openedx/core/djangoapps/user_authn/config/waffle.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Waffle flags and switches for user authn.
"""

from edx_toggles.toggles import WaffleSwitch
from edx_toggles.toggles import WaffleFlag, WaffleSwitch

_WAFFLE_NAMESPACE = 'user_authn'

Expand Down Expand Up @@ -31,3 +31,19 @@
ENABLE_PWNED_PASSWORD_API = WaffleSwitch(
f'{_WAFFLE_NAMESPACE}.enable_pwned_password_api', __name__
)

# .. toggle_name: user_authn.enable_enterprise_redirect_to_authn
# .. toggle_implementation: WaffleFlag
# .. toggle_default: False
# .. toggle_description: When enabled, allows Enterprise/B2B customers to be redirected to the AuthN MFE instead of
# the legacy Django login templates. This flag provides an incremental rollout mechanism for migrating Enterprise
# customers to the modern authentication experience. The flag has no effect on users with external authentication
# providers (SAML/TPA), who always remain on the legacy flow. B2C users are redirected to the MFE by default
# regardless of this flag.
# .. toggle_use_cases: opt_in
# .. toggle_creation_date: 2026-02-18
# .. toggle_warning: This flag only affects Enterprise customers without external auth providers (SAML/TPA).
# Enabling this flag for an Enterprise customer with complex SSO requirements may break authentication flows.
ENABLE_ENTERPRISE_REDIRECT_TO_AUTHN = WaffleFlag(
f'{_WAFFLE_NAMESPACE}.enable_enterprise_redirect_to_authn', __name__
)
26 changes: 19 additions & 7 deletions openedx/core/djangoapps/user_authn/views/login_form.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,8 @@
from openedx.core.djangoapps.user_api.accounts.utils import is_secondary_email_feature_enabled
from openedx.core.djangoapps.user_api.helpers import FormDescription
from openedx.core.djangoapps.user_authn.cookies import set_logged_in_cookies
from openedx.core.djangoapps.user_authn.toggles import (
is_require_third_party_auth_enabled,
should_redirect_to_authn_microfrontend,
)
from openedx.core.djangoapps.user_authn.config.waffle import ENABLE_ENTERPRISE_REDIRECT_TO_AUTHN
from openedx.core.djangoapps.user_authn.toggles import should_redirect_to_authn_microfrontend
from openedx.core.djangoapps.user_authn.views.password_reset import get_password_reset_form
from openedx.core.djangoapps.user_authn.views.registration_form import RegistrationFormFactory
from openedx.core.djangoapps.user_authn.views.utils import third_party_auth_context
Expand Down Expand Up @@ -202,10 +200,24 @@ def login_and_registration_form(request, initial_mode="login"):

enterprise_customer = enterprise_customer_for_request(request)

# Check for external providers (SAML/TPA) which must NEVER redirect to MFE
has_external_provider = bool(tpa_hint_provider or saml_provider)

# Determine eligibility based on segment
if enterprise_customer:
# Enterprise/B2B: Requires the specific rollout waffle flag
is_segment_eligible = ENABLE_ENTERPRISE_REDIRECT_TO_AUTHN.is_enabled()
else:
# B2C: Eligible by default
is_segment_eligible = True

# Redirect to authn MFE if all conditions are met:
# 1. MFE is globally enabled (should_redirect_to_authn_microfrontend)
# 2. User segment is eligible (B2C by default, or Enterprise with flag enabled)
# 3. No external auth provider is present (SAML/TPA must use legacy flow)
if should_redirect_to_authn_microfrontend() and \
not enterprise_customer and \
not tpa_hint_provider and \
not saml_provider:
is_segment_eligible and \
not has_external_provider:

# This is to handle a case where a logged-in cookie is not present but the user is authenticated.
# Note: If we don't handle this learner is redirected to authn MFE and then back to dashboard
Expand Down