Vue Router and Axios Interceptors: Synchronizing Session Expiration State
0 reputation · 15 May 2021, 06:47 UTC
0 reputation · 15 May 2021, 06:47 UTC
In a Vue.js application utilizing Pinia for state management and Axios for API communication, there is a functional boundary between the HTTP interceptor that detects expired credentials and the Vue Router guards that protect client-side routes.
When an Axios interceptor catches a 401 Unauthorized response, it must trigger a state change to invalidate the session. However, if the user is navigating through protected routes via the Vue Router, the local state may remain 'authenticated' until the next navigation guard execution or a full page refresh, potentially leading to a UI state that contradicts the server-side session status.
Given the need to maintain a least-privilege UI, the application must ensure that the transition from an authenticated to an unauthenticated state is atomic across both the network layer and the routing layer.
32275 reputation · 15 May 2021, 13:29 UTC
Make the Axios interceptor change a single source of truth in Pinia and trigger navigation once, and make Vue Router guards read that same Pinia flag synchronously. Do not let the interceptor and the guard each decide to redirect independently.
Centralize logout in the Pinia auth store. The interceptor calls the store action, the store clears the token and sets isAuthenticated = false, then the store or a router plugin performs a single programmatic navigation to login.
authStore.logout() once and set a flag sessionExpired.router.replace({ name: 'login', query: { expired: '1' } }). This is the only place that redirects.Keep the guard reactive to the same Pinia flag and avoid API calls inside guards.
authStore.isAuthenticated synchronously. If false, redirect to login immediately.v-if="authStore.isAuthenticated" or a layout guard so rendering is blocked before mount.An Axios response interceptor can centrally inspect HTTP error status codes for authentication failures and trigger a single logout routine, preventing scattered error handling across components.
Vue Router navigation guards can gate access to protected routes by checking a shared authentication state before allowing navigation.
When interceptor-driven redirects and router-guard redirects operate independently, double navigation, flicker, or missed cleanup can occur on session expiry.
Session expiration state should be held in a single reactive source, such as a Pinia auth store, so both the interceptor and router read the same flag.
isAuthenticated = false, optionally set sessionExpired = true.authStore.handle401() once per failure and does not redirect itself.router.replace to login.beforeEach guard checks authStore.isAuthenticated and redirects if false.Caution: Do not redirect inside the interceptor for requests that are part of the login or token refresh flow. Ensure router guards do not trigger API calls that themselves cause 401 handling, which can create circular redirects.
One diagnostic detail that changes the recommendation: Do you have an active refresh token flow that retries the original request on 401? If yes, the interceptor should attempt refresh first and only logout after refresh fails.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 15 May 2021, 09:46 UTC
To build on the suggested centralized logout pattern, it is important to account for concurrent API requests. If a page triggers multiple parallel requests that all return a 401 Unauthorized status, the interceptor may attempt to trigger the Pinia logout action and router redirection multiple times in a single tick.
To prevent redundant navigation calls and potential "Navigation Duplicated" warnings in Vue Router 4, implement an idempotency flag within the Pinia store:
isHandlingAuthError boolean to the auth store.true immediately upon the first 401 detection.Additionally, ensure the interceptor returns Promise.reject(error) after triggering the logout. This prevents the calling component from attempting to process a failed response as a success, which could lead to further UI inconsistencies before the redirect occurs.