Comprehensive Auth Hardening — Token Refresh, Route Guards, Session Timeout, Error Handling - #16
Open
Flashl3opard wants to merge 1 commit into
Open
Flashl3opard wants to merge 1 commit into
Flashl3opard wants to merge 1 commit into
Conversation
…sion timeout, 401/403 handling, security review
Contributor
|
could this be raised against the new repo as we have merged this repo across ready for release. So all additions should now be to https://github.com/openMF/paymenthub-ee-operationsui-react/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
EPIC PHEE-363
Summary
Implemented a complete auth hardening suite across 6 phases to make the Keycloak ROPC flow production-ready. The root issue was that
keycloak-jswasn't actually receiving tokens after login, preventing it from managing refresh and expiry. Now tokens are properly hydrated, silent refresh works on a proactive interval, protected routes enforce auth checks on every navigation, and 401/403 responses are handled gracefully.Changes
Phase 1: Token Hydration (Root Cause Fix)
src/modules/auth/Login.tsx— After ROPC login, now callskeycloak.init({ token, refreshToken, idToken })to give keycloak-js the tokens it needssrc/lib/keycloak/keycloak.ts— NewpersistTokens()/clearTokens()helpers centralize token storage (was scattered across 14+ raw localStorage calls)Phase 2: Silent Token Refresh
src/lib/keycloak/refresh.ts(new) — Wrapskeycloak.updateToken(300)with retry-once-after-2s fallback, built on keycloak-js's own mechanismsrc/lib/keycloak/KeycloakProvider.tsx— Refresh interval proactively refreshes tokens when <5 min remainPhase 3: Route Guarding
src/components/shared/ProtectedRoute.tsx(new) — Guards every navigation, checks auth state + token expiry on every route change (not just initial load)src/main.tsx— Wrapped in AuthRoot; all non-login routes protectedPhase 4: Session Timeout + Logout
src/lib/keycloak/useIdleTimer.ts(new) — 15-min idle threshold, warns at 13 min with modalsrc/components/shared/SessionTimeoutModal.tsx(new) — Styled to match existing dialogs; "Stay Logged In" refreshes token, timeout auto-logs outPhase 5: 401/403 Error Handling
src/lib/api/authInterceptors.ts(new) — Axios interceptors handle:refresh.ts, retries request once (guarded by_retryflag). On refresh failure, clears tokens + redirects to login.ForbiddenListener.tsx, redirects to/+ shows toast)src/lib/api/client.ts&src/lib/api/g2pConfig.ts— Both now usecreateAuthInterceptors()src/components/shared/ForbiddenListener.tsx(new) — Reacts to 'forbidden' event; redirects + notifies userPhase 6: Security Documentation
README.md— Added "Security" section documenting:Utilities
src/lib/events.ts(new) — Event bus for 'forbidden' | 'activity' events (decouples interceptors from UI)Testing
New test files:
src/lib/keycloak/refresh.test.ts— 5 tests (refresh success, refresh failure, retry logic)src/lib/keycloak/useIdleTimer.test.ts— 4 tests (idle detection, warn state, reset)src/lib/api/authInterceptors.test.ts— 4 tests (401→retry, 401→fail, 403→event, redirectToLogin export)Results:
tsc --noEmit— clean, no type errorsKey Insights
keycloak.init()with actual tokens fixed everything downstream.updateToken()handles refresh properly once it has the tokens; we just wrapped it with retry logic.Impact
Remaining
Checklist