fix(oidc): persist tokens before navigating + router-push internal return_to #84
No reviewers
Labels
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
psa-systems/mokosh-apps!84
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/auth-callback-persists-tokens-before-nav"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
mokosh-server's E2E suite started failing on
[setup] capture bearer from the SPA login: after OIDC completed, the SPA landed on /dashboard, the router showed an extra OIDC handshake fire, and no request ever carriedAuthorization: Bearer. The setup's 30s poll for any Bearer-carrying request hit zero.Two bugs, one fix on each axis:
AuthCallbacknever persisted the token bundle to sessionStorage. The component wroteauth.user, set the in-memory access-token holder, and then calledlocation.set_href(return_to)for any absolute return_to value (whichstart_login("/dashboard")from the Login component triggers). A hard reload tore the in-memoryAuthContextdown between the write and the next boot, andrehydrate_from_storagefound nothing becausesave_authwas only called insideuse_token_refresh's 60s-later rotation path. The SPA booted unauthenticated, AuthGuard fired another start_login, and the loop is exactly what the test trail showed.The original behaviour worked by accident:
use_memberships_loaderused to fireGET /v1/auth/membershipsagainst bunyip at the same render cycle as the AuthCallback write, and that cross-origin call carried the Bearer header BEFORE the reload tore everything down. mokosh-apps PR #79 replaced that fetch with local synthesis (because bunyip'sAuthenticatedUserextractor was not accepting OIDC at+jwt, see BUNYIP-55), so the accidental capture was gone and the underlying token-persistence bug surfaced.Fix:
StoredTokensbundle to sessionStorage BEFORE any navigation.rehydrate_from_storagenow finds the bundle on the very next boot, and the SPA is authenticated immediately regardless of whether AuthCallback router-pushed or hard-reloaded./, not//), prefernavigator.push(Dashboard)so the in-memory signal carries through without a reload at all. Cross-origin or otherwise unrecognised return_to values still fall back toset_href, but the sessionStorage save above now covers that path too.The Dioxus router only knows about
Routeenum variants, so an internal path beyond/dashboardcollapses toDashboardfor the moment. The set of post-login return_to paths in use today is{ "", "/", "/dashboard" }; this collapse is a no-op for all of them. Expand the matrix when a new return-to target is introduced.No server-side change. Test plan: rerun the mokosh-server E2E suite once this and the deploy land; setup should capture a bearer on the first
/api/v1/*fetch the dashboard fires.mokosh-server's E2E suite started failing on `[setup] capture bearer from the SPA login`: after OIDC completed, the SPA landed on /dashboard, the router showed an extra OIDC handshake fire, and no request ever carried `Authorization: Bearer`. The setup's 30s poll for any Bearer-carrying request hit zero. Two bugs, one fix on each axis: `AuthCallback` never persisted the token bundle to sessionStorage. The component wrote `auth.user`, set the in-memory access-token holder, and then called `location.set_href(return_to)` for any absolute return_to value (which `start_login("/dashboard")` from the Login component triggers). A hard reload tore the in-memory `AuthContext` down between the write and the next boot, and `rehydrate_from_storage` found nothing because `save_auth` was only called inside `use_token_refresh`'s 60s-later rotation path. The SPA booted unauthenticated, AuthGuard fired another start_login, and the loop is exactly what the test trail showed. The original behaviour worked by accident: `use_memberships_loader` used to fire `GET /v1/auth/memberships` against bunyip at the same render cycle as the AuthCallback write, and that cross-origin call carried the Bearer header BEFORE the reload tore everything down. mokosh-apps PR #79 replaced that fetch with local synthesis (because bunyip's `AuthenticatedUser` extractor was not accepting OIDC at+jwt, see BUNYIP-55), so the accidental capture was gone and the underlying token-persistence bug surfaced. Fix: - Save the full `StoredTokens` bundle to sessionStorage BEFORE any navigation. `rehydrate_from_storage` now finds the bundle on the very next boot, and the SPA is authenticated immediately regardless of whether AuthCallback router-pushed or hard-reloaded. - For internal return_to paths (starting with `/`, not `//`), prefer `navigator.push(Dashboard)` so the in-memory signal carries through without a reload at all. Cross-origin or otherwise unrecognised return_to values still fall back to `set_href`, but the sessionStorage save above now covers that path too. The Dioxus router only knows about `Route` enum variants, so an internal path beyond `/dashboard` collapses to `Dashboard` for the moment. The set of post-login return_to paths in use today is `{ "", "/", "/dashboard" }`; this collapse is a no-op for all of them. Expand the matrix when a new return-to target is introduced. No server-side change. Test plan: rerun the mokosh-server E2E suite once this and the deploy land; setup should capture a bearer on the first `/api/v1/*` fetch the dashboard fires.