Skip to content

Dev-mode concurrent token refresh race logs the user out (StrictMode double refresh) #916

Description

@xyimatvoid

Target branch

main

Classification

Bug (auth, admin frontend; dev-mode symptom, latent race in production)

Problem

On next dev, loading a page with no access token in memory fires two concurrent [Auth] No access token found. Attempting to refresh... calls (React StrictMode double effect). The first refresh succeeds and rotates the refresh token; the second sends the now-stale token, receives 401, and auth-store treats it as a hard failure and logs the user out — every hard navigation bounces to /login.

Observed at packages/frontend/src/stores/auth-store.ts:291-295 while testing #914:

  1. No access token found. Attempting to refresh... ×2 (~2ms apart)
  2. Token refreshed successfully
  3. POST /api/v1/auth/refresh → 401
  4. Token refresh failed. User needs to log in again. → redirect to login

Expected behavior

Concurrent refresh attempts should be deduplicated (single in-flight refresh promise shared by callers). A refresh 401 that races a successful rotation should not destroy a session that just obtained a valid access token.

Suspected failure path

auth-store.ts refresh flow has no mutex/in-flight promise; refresh-token rotation on the backend invalidates the first token as soon as the second request is in flight.

Repro

  1. pnpm dev the admin frontend against the quickstart backend
  2. Log in, then hard-reload any authenticated page
  3. Watch console: double refresh warning, then 401 + forced logout

Scope

  • packages/frontend/src/stores/auth-store.ts (frontend-user likely shares the pattern — verify)

Acceptance criteria

  • Only one refresh request in flight at a time; concurrent callers await the same promise
  • Hard reloads on next dev no longer bounce to /login
  • Production flow unchanged

Out of scope

  • Backend refresh-token rotation semantics

Found while testing #914 / #915.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions