Overview
The axios request interceptor rejects with code: 'SESSION_EXPIRED' and immediately calls useAppStore.getState().logout() whenever sessionExpiresAt has passed. That check uses local device time and runs before any network attempt, so a device with a skewed clock — or one that has been offline long enough for a token to expire while an OTA-cached session is still valid server-side — logs the user out with no opportunity to recover. SessionExpiredModal exists but the rejection path does not surface it.
Specifications
Features:
- A grace window that attempts a refresh before forcing logout
- Clock-skew tolerance derived from a server
Date header rather than device time alone
SessionExpiredModal shown instead of a silent logout
Tasks:
- Record server-client clock offset from response
Date headers and apply it to expiry checks
- Attempt a refresh before logging out when expiry is detected locally
- Route the
SESSION_EXPIRED rejection through SessionExpiredModal
- Add tests covering a skewed device clock and an offline expiry
Impacted Files:
src/services/api/axios.config.ts
src/components/common/SessionExpiredModal.tsx
src/services/sessionRestoration.ts
src/__tests__/services/sessionExpiry.test.ts
Acceptance Criteria
- A skewed device clock does not force a logout
- The user sees an explanation rather than being silently signed out
- A refresh is attempted before the session is discarded
Overview
The axios request interceptor rejects with
code: 'SESSION_EXPIRED'and immediately callsuseAppStore.getState().logout()wheneversessionExpiresAthas passed. That check uses local device time and runs before any network attempt, so a device with a skewed clock — or one that has been offline long enough for a token to expire while an OTA-cached session is still valid server-side — logs the user out with no opportunity to recover.SessionExpiredModalexists but the rejection path does not surface it.Specifications
Features:
Dateheader rather than device time aloneSessionExpiredModalshown instead of a silent logoutTasks:
Dateheaders and apply it to expiry checksSESSION_EXPIREDrejection throughSessionExpiredModalImpacted Files:
src/services/api/axios.config.tssrc/components/common/SessionExpiredModal.tsxsrc/services/sessionRestoration.tssrc/__tests__/services/sessionExpiry.test.tsAcceptance Criteria