Skip to content

Render the enterprise-branded logistration experience in the authn MFE #1691

Description

@feanil

Context

We want to retire the legacy server-rendered login/registration page (DEPR openedx/public-engineering#81, tracked in openedx/openedx-platform#38936), but we can't yet, and enterprise is the reason. The legacy page renders an enterprise-branded logistration experience (branded sidebar, provider suppression, consent-gated SSO registration) that frontend-app-authn doesn't, so the platform deliberately keeps enterprise/SSO learners on the old page. You can see the guard in openedx/core/djangoapps/user_authn/views/login_form.py:176-190:

has_external_provider = bool(tpa_hint_provider or saml_provider)
# NOTE: SAML/TPA users authenticating externally must remain on the legacy login/registration page
# because the new AuthN MFE does not yet fully support provider branding, hinted-login dialog, etc.
# TODO: Remove the `has_external_provider` check as soon as the AuthN MFE is fully-featured.
if should_redirect_to_authn_microfrontend() and not has_external_provider:
    return redirect(settings.AUTHN_MICROFRONTEND_URL + url_path)

This issue is about building that enterprise experience in the MFE so we can drop the guard and remove the legacy page.

Groundwork already in place

The backend was refactored so enterprise logic reaches logistration (the MFE included) through openedx-filters pipeline steps instead of inline platform code:

Keeping enterprise pluggable (open question)

Enterprise is intentionally not built into the platform by default - that's the whole point of the filter refactor above: the platform ships no enterprise code, and edx-enterprise plugs in. The MFE should hold the same line, so I don't think we want to hardcode the enterprise experience into frontend-app-authn. The likely shape is a frontend plugin that installs into authn plugin slots and renders enterprise from the enterpriseBranding context - the frontend counterpart to how edx-enterprise plugs into the backend - but the details are unclear, and pinning them down is part of this work:

  • What slots does the authn MFE need to expose for this - an enterprise sidebar region, the provider list, messaging, registration fields? Today there's only LoginComponentSlot, so this overlaps with Plugin slots and customization settings for authn #1686 (plugin slots for authn).
  • Where does the enterprise plugin live and who owns it - a separate frontend package that's the edx-enterprise counterpart?
  • How does the plugin get the context - read enterpriseBranding off the mfe_context the core app already fetches, or fetch its own?

So full implementation is unclear precisely because enterprise is meant to be pluggable. Settling this architecture is the first task, ahead of the rendering itself.

What's left to do

1. Populate the enterpriseBranding payload (backend dependency). AuthnMFEEnterpriseContextEnricher builds its payload from build_enterprise_branding_for_authn_mfe(...), which isn't implemented yet - it's imported with a None fallback (edx-enterprise enterprise/filters/logistration.py:40-41) and is absent from openedx-platform master. This helper (referenced under ENT-11576) has to land so /api/mfe_context actually returns enterprise branding. It may be owned separately; I'm calling it out as a prerequisite.

2. Render the enterprise experience (as a plugin, per the open question above). Today the MFE has none, and the DISABLE_ENTERPRISE_LOGIN flag doesn't help: setting it false only swaps the institution-login button for a link out to the LMS /enterprise/login page (ThirdPartyAuth.jsx:47-72), it doesn't render any enterprise branding, suppression, or consent - so flipping it isn't a solution. EnterpriseSSO.jsx is likewise just a generic single-provider button. We need parity with the legacy openedx/features/enterprise_support/ behavior:

  • Enterprise sidebar / branding - consume enterpriseBranding and render the enterprise logo + branded welcome.
  • Generic-provider suppression - in an enterprise SSO context, show only the enterprise provider and hide the generic social/TPA providers.
  • Consent-gated auto-registration - for skip_registration_form SSO, don't silently auto-submit; show the auto-register welcome message and a "Continue" button.
  • Enterprise-branded TPA error messaging ("not authorized via this channel / contact your administrator") instead of the generic error.
  • Enterprise registration-field handling - drop excluded fields (ENTERPRISE_EXCLUDED_REGISTRATION_FIELDS) and show SSO-synced profile fields read-only.
  • Account-linking + multiple-enterprise selection - the "you already have an account with your {enterprise} email" copy, and routing learners in more than one enterprise to the selection page (/enterprise/select/active, LMS-hosted). Confirm how much of this is MFE-side vs. delegated.

3. Confirm what already flows vs. what's net-new. LoginFormEnterpriseOverrides / RegistrationFormEnterpriseOverrides modify the shared form-description context the MFE already reads, so some of the above (provider suppression, consent-gated auto-register, field handling) may already arrive via /api/mfe_context. Worth auditing which overrides reach the MFE today before building anything new.

4. Remove the platform guard. Once the MFE renders these flows at parity, remove the has_external_provider guard in login_form.py:176-190 so enterprise/SSO learners are served by the MFE. That's the step that finally unblocks the legacy removal.

Definition of done

  • A decided pluggable architecture - which authn slots to expose and where the enterprise plugin lives - so enterprise stays opt-in, not built into the MFE by default.
  • /api/mfe_context returns a populated enterpriseBranding payload.
  • frontend-app-authn renders enterprise SSO / proxy-login flows at parity with the legacy page.
  • The has_external_provider guard can be removed and enterprise/SSO learners are served by the MFE.

References

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions