fix(auth) coordinate token refresh across concurrent requests and tabs #63
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix-concurrent-token-refresh"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #49: concurrent 401s each called
/auth/refreshwith the same refresh-token cookie. The backend rotates that cookie on every refresh, so a losing refresh got 401 and logged the user out even when another had just succeeded. The same race exists between tabs, which share the cookie and the localStorage session.Changes
src/utils/concurrencyUtils.ts(new):createSingleFlight: concurrent calls share one run.runWithCrossTabLock: runs an operation under a Web Lock (navigator.locks, built into the browser, no dependency). The wait for the lock is capped (10 s for the refresh), so a frozen background tab can't block the others. On timeout, or without lock support, the operation runs without the lock.AuthRestResource.refresh(rejectedToken):/auth/refresh.apiClient: passes the request's token torefresh(). The session is still cleared only when the refresh fails or the retry gets another 401.src/utils/tests/concurrencyUtils.test.ts(8 cases).docs/adr/2026-10-24-coordinated-token-refresh.md. It covers the rejected alternatives, including a backend grace window for the rotated token.docs/architecture.mdis updated.Verification
npm run test,npm run build,npm run lint: pass (the lint warnings are the existing two inMealPlanDayProvider.tsx)./shopping-list/<id>. Expect exactly one/auth/refreshand the user stays logged in.🤖 Generated with Claude Code