Re-authenticate instead of going blank when the session is lost#3042
Merged
Conversation
App.vue renders the whole app behind shouldShowApp (authEnabled, isAuthenticated, isAnonymousRoute). When the access token expired and silent renewal failed, isAuthenticated flipped to false and the app rendered nothing, requiring a manual browser refresh to recover. Watch for the session being lost while running and re-trigger authentication: with a live identity-provider session this is a silent redirect round-trip; otherwise the user lands on the provider's login page. Skipped on anonymous routes and while a sign-in is already in progress.
5bdb083 to
a9b62fe
Compare
PhilBastian
reviewed
Jun 26, 2026
…watch Addresses review feedback on #3042: the re-authentication logic doesn't belong in App.vue, and watching the isAuthenticated proxy state is indirect. Move recovery into the auth domain: useAuth now reacts to the addAccessTokenExpired and addSilentRenewError OIDC events directly and re-authenticates via signinRedirect, guarded against re-entrancy and the logged-out route. This also distinguishes session loss from an intentional logout (addUserUnloaded), which must not re-trigger authentication, and recovers proactively on a silent-renewal error instead of waiting for the token to fully expire. App.vue is now display-only. Its spec covers the layout gating; useAuth.spec covers the event-driven recovery.
johnsimons
reviewed
Jun 26, 2026
PhilBastian
approved these changes
Jun 28, 2026
PhilBastian
left a comment
Contributor
There was a problem hiding this comment.
looks good with John's suggested changes
warwickschroeder
approved these changes
Jun 29, 2026
Co-authored-by: John Simons <john@thesimonshouse.com>
The recovery fix lives in useAuth.ts and is covered by useAuth.spec.ts. App.spec.ts only exercised pre-existing App.vue layout gating that this PR does not change, so it is out of scope.
The addAccessTokenExpired/addSilentRenewError handlers were flush at column 0 with mixed tabs/spaces. Indent them to match the surrounding block (Prettier clean).
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.
Problem
When OIDC auth is enabled and the access token expires (and silent renewal does
not succeed),
App.vuerenders nothing and the user has to manually refresh thebrowser to recover.
App.vuegates the entire app behindshouldShowApp(authEnabled,isAuthenticated,isAnonymousRoute). On token expiry,oidc-client-tsclearsthe token,
isAuthenticatedflips tofalse, and thatv-ifrenders nothing.Nothing re-triggers authentication, so the page stays blank until a refresh
re-runs the auth flow on mount.
Fix
Watch for the session being lost while the app is running and re-trigger
authentication via the existing
useAuth().authenticate()flow:the user keeps working.
already in progress, to avoid loops.
Tests
App.spec.ts: re-authenticates on token loss; does not while alreadyauthenticating; does not on an anonymous route.
Notes
masterdirectly.identity-provider configuration concern (the provider must grant
offline_accessso a refresh token is issued); ServicePulse already requests it.