Skip to content

feat(auth): single-flight token refresh with cross-tab coordination - #20

Open
armorbreak001 wants to merge 2 commits into
shaiananvari8:mainfrom
armorbreak001:feat/single-flight-token-refresh
Open

armorbreak001 wants to merge 2 commits into
shaiananvari8:mainfrom
armorbreak001:feat/single-flight-token-refresh

Conversation

@armorbreak001

Copy link
Copy Markdown

Summary

Fixes the token-refresh race condition in frontend/src/services/auth.ts where concurrent refresh callers (multiple tabs/components) each issued independent refresh requests. Implements single-flight coordination so all concurrent callers share one in-flight refresh operation, with safe cross-tab notification via BroadcastChannel and proper cleanup on both success and failure.

Closes #1

Changes

  • frontend/src/services/auth.ts

    • Added inflightRefresh shared promise: concurrent refreshTokens() callers await the same operation and resolve from the same final token state
    • Failed refresh attempts clear the in-flight marker (in finally) so a later refresh can retry normally
    • Added broadcastRefreshResult() — posts refresh-success / refresh-failed to a tot_auth_refresh BroadcastChannel; silently no-ops where BroadcastChannel is unavailable; no raw tokens are logged or broadcast
    • Added setupCrossTabListener() — on refresh-success other tabs reload tokens from storage and reschedule refresh; on refresh-failed they clear local session state
    • logout() now cancels any in-flight refresh so pending refreshes cannot resurrect state
    • Documented the behavior in the module header comment and inline near the refresh implementation
  • frontend/src/__tests__/single-flight-refresh.test.js (new)

    • 8 focused tests using Node's built-in test runner (zero new dependencies)

Testing

  • node --test src/__tests__/single-flight-refresh.test.js8/8 pass (~170ms)
    • concurrent callers share one in-flight operation (asserts exactly 1 API call for 2 concurrent refreshes)
    • failure clears in-flight marker; retry succeeds afterwards
    • sequential refreshes allowed after completion
    • success/failure broadcast via channel
  • python3 build.py → completed; diagnostic committed as build-94e0fb08 (.json + 7 .logd chunks, reassembly command in build output; chunk password: 52e21717e4d8555f95ab)

Checklist

  • Relevant modules affected by these changes build locally
  • Tests pass locally
  • Diagnostic build log is committed in this PR (diagnostic/build-94e0fb08*)
  • Documentation has been updated, if applicable (module header + inline docs)
  • Configuration or schema changes are documented, if applicable (N/A — no config/schema changes)
  • No generated build artifacts are committed, except the required diagnostic build log
  • Changes are scoped to the PR purpose and avoid unrelated cleanup
  • Security, privacy, and error-handling implications have been considered (no token logging; failure paths clear state; BroadcastChannel failures are silent no-ops)

  • I would like to request that my diagnostic build log is removed before merging

Fixes the token-refresh race condition where concurrent callers
(multiple tabs/components) each issued independent refresh requests,
risking stale token writes and inconsistent session state.

- Shared in-flight promise: concurrent refresh callers await the
  same operation and resolve from one final token state
- Failure clears the in-flight marker so a later refresh retries
- BroadcastChannel notifications ('tot_auth_refresh') propagate
  success/failure across tabs; other tabs reload tokens from
  storage on success and clear state on failure; falls back to
  silent no-op where BroadcastChannel is unavailable; no raw
  tokens are logged or broadcast
- Logout cancels any in-flight refresh
- Documented behavior in module header + inline comments
- 8 focused tests (node:test) covering concurrent success,
  failure retry, sequential refreshes, and broadcasts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[$35 BOUNTY] [TypeScript] Add single-flight token refresh handling

1 participant