Skip to content

feat: SPA navigation for post-auth redirects#1647

Open
arbrandes wants to merge 4 commits intoopenedx:frontend-basefrom
arbrandes:login-redirection
Open

feat: SPA navigation for post-auth redirects#1647
arbrandes wants to merge 4 commits intoopenedx:frontend-basefrom
arbrandes:login-redirection

Conversation

@arbrandes
Copy link
Contributor

@arbrandes arbrandes commented Mar 13, 2026

Description

When a user navigates to a protected SPA route while logged out, authenticatedLoader redirects to /authn/login?next=/some-path. Previously, this relative next param was forwarded to the LMS backend, which resolved it against itself and returned an absolute LMS URL, causing a full page navigation away from the SPA shell. Now the relative path is stripped from the API payload and handled locally after login/registration succeeds, using <Navigate> for seamless SPA navigation.

This also revealed that the authn app's navigation was still using absolute path constants like '/login', which don't resolve correctly under the /authn route prefix. All navigation now goes through getUrlByRouteRole() to resolve URLs from the route config, and components like UnAuthOnlyRoute, ChangePasswordPrompt, and ProgressiveProfiling use SPA navigation instead of window.location.href when the target is internal.

Finally, when the LMS backend returns its own dashboard URL as redirect_url after login or registration, it is normalized to the role-based dashboard URL via a shared normalizeRedirectUrl() utility, so RedirectLogistration can navigate without a full page reload.

Depends on openedx/frontend-base#183, and indirectly on openedx/frontend-app-learner-dashboard#806.

Note to reviewer

Start the review with src/constants.ts and src/routes.tsx. It makes the rest easier to understand.

Testing

Set up a complete frontend-template-site with all the latest changes in frontend-base, authn, and learner-dashboard. After that, make sure login and registration still work, including by manually navigating to /learner-dashboard without having logged in first (if you installed openedx/frontend-app-learner-dashboard#806).

LLM usage notice

Built with assistance from Claude models (mostly Opus 4.6).

@codecov
Copy link

codecov bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 83.33333% with 13 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (frontend-base@c0cf462). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...essive-profiling/ProgressiveProfilingPageModal.jsx 20.00% 4 Missing ⚠️
src/login/LoginPage.jsx 75.00% 2 Missing ⚠️
src/register/RegistrationPage.jsx 75.00% 2 Missing ⚠️
src/common-components/EnterpriseSSO.jsx 50.00% 1 Missing ⚠️
src/common-components/RedirectLogistration.jsx 50.00% 1 Missing ⚠️
src/login/ChangePasswordPrompt.jsx 83.33% 1 Missing ⚠️
src/logistration/Logistration.jsx 87.50% 1 Missing ⚠️
src/progressive-profiling/ProgressiveProfiling.jsx 80.00% 1 Missing ⚠️
Additional details and impacted files
@@               Coverage Diff                @@
##             frontend-base    #1647   +/-   ##
================================================
  Coverage                 ?   92.12%           
================================================
  Files                    ?       92           
  Lines                    ?     2045           
  Branches                 ?      585           
================================================
  Hits                     ?     1884           
  Misses                   ?      158           
  Partials                 ?        3           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@jesusbalderramawgu jesusbalderramawgu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you, this is a great catch

@arbrandes arbrandes force-pushed the login-redirection branch 3 times, most recently from b04929e to 4ff413c Compare March 16, 2026 21:10
@arbrandes arbrandes changed the title feat: handle relative next param locally after login/registration feat: SPA navigation for post-auth redirects Mar 16, 2026
arbrandes and others added 4 commits March 16, 2026 18:54
When a user navigates to a protected SPA route while logged out, the
authenticatedLoader redirects to /authn/login?next=%2Fsome-path. Previously,
this relative next param was sent to the LMS backend, which resolved it
against itself and returned an absolute LMS URL — causing a full page
navigation away from the SPA shell.

Now, when next starts with /, it is stripped from the API payload and
handled locally: after login/registration succeeds, fetchAuthenticatedUser
refreshes the auth cache so authenticatedLoader allows the target route,
RedirectLogistration uses <Navigate> for SPA navigation, and
hydrateAuthenticatedUser runs in the background to populate the full
user profile (avatar, etc.) in the header.

Also applies the same relative-path SPA navigation pattern to
ProgressiveProfilingPageModal and replaces the hardcoded LMS dashboard
fallback in the registration API with getUrlByRouteRole for consistency.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Routes are nested by default, but navigation constants used absolute
paths like '/login', causing navigate() and <Navigate> to go to /login
instead of /authn/login.

Replace path constants in navigation calls with getUrlByRouteRole()
where possible, which resolves the URL for a given route role from the
route config. Path constants are still generally useful, but are now all
relative (and camelCase).

Centralize route roles, path segments, and the dashboard role in
src/constants.ts.

Last but not least, prefer SPA navigation (<Navigate>, useNavigate) over
window.location.href where the target URL may be internal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the backend returns the LMS dashboard URL as redirect_url after
login or registration, replace it with getUrlByRouteRole(dashboardRole)
so that RedirectLogistration can use <Navigate> for SPA navigation
instead of a full page reload.

Also hydrate the authenticated user before SPA navigation so the shell
header displays the user's name.  This applies the same
fetchAuthenticatedUser/hydrateAuthenticatedUser pattern already used for
the localNextPath flow to any redirect URL that starts with '/'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants