fix(#403): handle account-not-provisioned auth errors and gate branded header#428
Merged
Conversation
added 3 commits
June 23, 2026 17:14
…authenticated users now hit a terminal "contact your administrator" state at /signin instead of looping through "Your session has expired".
7 tasks
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.
Summary
Closes the FE half of #403. Rehomed from #418 by @tarratsco (Onix Tarrats Calderon) onto an internal branch so CI can run with secrets; original authorship is preserved across all three commits. Rebased onto current
main(Title.tsx auto-merged cleanly with the #425 datacall-allowlist change; both survived).Pre-existing bug: an IdP-authenticated identity with no ZTMF account (or a soft-deleted one) landed on LoginPage with "Your session has expired" and an infinite sign-in loop. The IdP session was valid so the ALB never re-prompted; the SPA 401'd on
/users/currentand rendered the wrong copy.This adds a
NO_ACCOUNTsign-in reason driven by a403 + ACCOUNT_NOT_PROVISIONEDsignal from the paired BE PR, renders a terminal "contact your administrator" state with no retry CTA, and preserves the existingEXPIREDhandling for genuine 401s. Also gates the branded header to hide whenever LoginPage is the body, not just on the/signinURL.Backend dependency
Pairs with CMS-Enterprise/ztmf#360. The
NO_ACCOUNTterminal state only renders once the BE emits the newcodefield.Deploy order: FE first, BE second. Forward-compatible: with old BE deployed, every new path stays dormant and behavior matches today.
Changes
utils/authCodes.ts(new) — mirrors BE auth-package constants + FESignInReasonsutils/authInterceptor.ts— branches onresponse.data.code(NO_ACCOUNT, FORBIDDEN_ORIGIN, controller-403 unchanged)router/authLoader.ts— discriminated return for the two auth-failure shapesviews/LoginPage/LoginPage.tsx— terminalNoAccountTerminal, BE message verbatimutils/apiErrors.ts— surfacecodefor callersviews/Title/Title.tsx— header gate + sharedAuthLoaderDatatypeVerification
codeundefined → 401 stays EXPIRED, 403 falls through to existing controller-403 toastNon-blocking follow-ups (from review, optional)
NO_ACCOUNTfallback uses the permission copy, while the loader path lets LoginPage own the fallback — divergent copy only if BE sends an emptyerrorbody (paired BE always sends one). Could passreasononly and let LoginPage own the fallback.AuthCodes.UNAUTHORIZEDis declared for BE-mirror docs but not branched on (any 401 is treated as EXPIRED). Harmless.Credit: @tarratsco. Supersedes #418.