feat(auth): unify token lifecycle with coordinated silent refresh across REST, WebSocket, and offline queues - #1150
Merged
RUKAYAT-CODER merged 1 commit intoAug 23, 2026
Conversation
Introduces a single TokenManager that owns the access/refresh tokens so the REST client, WebSocket connections, the notification socket and the offline replay queue all share one credential and one refresh path. - TokenManager (src/lib/auth/tokenManager.ts): single-flight refresh so concurrent 401s collapse into one /auth/refresh call; proactive silent refresh a configurable skew before exp; token:rotated / token:revoked / auth:logout events; auth lifecycle metrics. - REST: api.ts sources its token from the manager and performs one coordinated refresh + replay on 401; apiInterceptors attaches a freshly refreshed token and routes 401 through the manager, hard-logging-out only when the refresh itself fails. - Sockets: websocketManager re-authenticates live connections on rotation and drops them on revocation; the notification socket does the same in place. - Offline: offlineApi and offlineSync gate replay on a valid token, refreshing silently and refusing (dead-letter) when logged out so the queue is not burned against a dead credential. - jwt.ts adds a client-safe decode and a detailed verifier that surfaces the exp/nbf/signature failure reason; config/constants add the refresh endpoint and skew. Adds unit tests covering single-flight dedupe, skew scheduling, rotation and revocation, persistence and forced logout.
oladev2026-tech
force-pushed
the
feat/1142-unified-token-lifecycle
branch
from
August 23, 2026 20:57
bffc950 to
367328b
Compare
Contributor
|
Thank you for contributing to the project. |
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.
Closes #1142
Summary
Introduces a single
TokenManagerthat owns the authentication token lifecycle, so the REST client, WebSocket connections, the notification socket and the offline replay queue all obtain their token from one place, share one refresh path, and react to rotation/revocation consistently.What changed
TokenManager(src/lib/auth/tokenManager.ts, new) — the single source of truth:/auth/refreshrequest, so a burst of 401s collapses into a single network round-trip (no thundering herd).exp, so long-lived sockets and queued offline operations never carry an about-to-lapse token.token:rotated/token:revoked/auth:logoutlet consumers re-authenticate or tear down instead of each discovering the change on its own failed request.auth.refresh_success,auth.refresh_failure,auth.token_rotated,auth.forced_logout.api.ts,apiInterceptors.ts) — the client sources its token from the manager, proactively refreshes before sending, and performs one coordinated refresh + replay on a 401 (guarded against loops). The request interceptor attaches a freshly-refreshed token; the error interceptor hard-logs-out only when the refresh itself fails.websocketManager.ts,notifications/socket.ts) — re-authenticate live connections in place ontoken:rotatedand disconnect ontoken:revoked, so a revoked session cannot keep receiving realtime data.offlineApi.ts,offlineSync.ts) — replay is gated on a valid token: it refreshes silently, and refuses (dead-letters viaOfflineAuthRequiredError/ skips the drain) when logged out, rather than burning retries against a dead credential.jwt.tsgains a client-safedecodeTokenPayloadand averifyTokenDetailedthat surfaces the specificexp/nbf/signature failure reason;environment.ts/app.constants.tsadd the refresh endpoint and skew;monitoring/metrics.tsadds a typedrecordAuthMetric.Acceptance criteria
Verification
All repo CI checks pass locally:
pnpm run type-check,pnpm run lint(--max-warnings=0),pnpm run validate:ui,pnpm run validate:web3,pnpm run build, and the new Vitest suite (13/13 passing) for the token manager.