Skip to content

feat(api): guarded single-flight token refresh with one retry#13

Open
leo202000 wants to merge 2 commits into
9904099:mainfrom
leo202000:feat/guarded-api-token-refresh
Open

feat(api): guarded single-flight token refresh with one retry#13
leo202000 wants to merge 2 commits into
9904099:mainfrom
leo202000:feat/guarded-api-token-refresh

Conversation

@leo202000

Copy link
Copy Markdown

Closes #2.

Summary

Implements a guarded token refresh flow in frontend/src/services/api.ts so concurrent 401 responses share a single in-flight /auth/refresh operation and the original request is retried exactly once with refreshed credentials.

Changes

  • AuthenticationError (typed, code 401) surfaced when refresh fails.
  • refreshAuthTokens() single-flight guard: concurrent callers share one in-flight refresh promise; the refresh request uses a raw fetch (bypassing request()) so a 401/403 from /auth/refresh cannot recurse.
  • request() detects 401, dedupes refresh, retries the original request exactly once (preserving method/headers/body via re-applied interceptors), clears auth state and throws AuthenticationError on failure. At most one refresh per request() call prevents loops.
  • Auth state kept in sync across the legacy auth_token key and the tot_auth_tokens bundle so the retried request picks up the new access token.
  • Public auth API (get/post/put/patch/del, Endpoints, interceptors) unchanged.

Validation

  • python3 build.py ran; encrypted diagnostic bundle included:
    • diagnostic/build-eae330fb.logd (DIAG magic, 13919 bytes, >=10240)
    • diagnostic/build-eae330fb.json (metadata + decrypt password)

Tests

  • frontend/src/services/tests/api.refresh.test.ts (vitest, jsdom): concurrent 401s share one refresh; successful single retry; refresh failure clears auth + throws AuthenticationError; no loop when /auth/refresh returns 401.
  • Run with npm test (vitest devDependency + vitest.config.ts added; test files excluded from the tsc -b build via tsconfig exclude).

Closes mannowell#2. Adds a single-flight refresh guard so concurrent 401 responses
share one in-flight /auth/refresh operation, retries the original request
exactly once with refreshed credentials (preserving method/headers/body),
clears auth state and surfaces a typed AuthenticationError on failure, and
avoids retry loops when the refresh endpoint itself returns 401/403.

- export AuthenticationError + refreshAuthTokens (single-flight)
- request() detects 401, dedupes refresh, retries once, throws typed error
- vitest suite: concurrent 401s, successful retry, refresh failure, no-loop
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.

[$45 BOUNTY] [TypeScript] Add guarded API token refresh handling

1 participant