-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Description
Describe the bug
The token refresh mechanism in the frontend may use a stale refresh token due to how the React Query queryFn captures variables from the render scope in AuthUserProvider.
Because the refresh query uses a static queryKey and the refresh token is captured in a closure, the query function may continue using an old refresh token even after the token has been rotated and updated in localStorage. This leads to unexpected session expiration or authentication failures during long-running sessions.
Relevant File
src/Providers/AuthUserProvider.tsx
Current Implementation (Simplified)
useQuery({
queryKey: ["user-refresh-token"],
queryFn: () => authApi.refresh({ refresh: refreshToken }),
refetchInterval: careConfig.auth.tokenRefreshInterval,
});The Issue:
Here, refreshToken is read from the render scope. If the backend rotates the refresh token and a new token is written to localStorage, the queryFn may continue using the old token until the component re-renders. Because the queryKey is static (["user-refresh-token"]), React Query does not necessarily recreate the queryFn, allowing the stale token to persist across refresh intervals.
To Reproduce
- Log in to the application normally.
- The frontend stores
care_access_tokenandcare_refresh_tokeninlocalStorage. - The token refresh query runs periodically using
refetchInterval. - The backend rotates the refresh token and returns a new one.
- The frontend updates the refresh token in
localStorage. - The next refresh interval fires.
- The
queryFnstill uses the old refresh token captured in the closure. - The backend rejects the refresh request, causing the session to expire unexpectedly.
Expected behavior
- The refresh mechanism should always use the latest refresh token stored in
localStorage. - Token refresh requests should succeed as long as a valid refresh token exists, preventing unexpected session expiration during normal usage.
Screenshots
Not applicable — this is a logic issue in the authentication flow rather than a UI issue.
Environment
- Desktop: Any (Chrome / Firefox / Safari)
- Smartphone: Any
Additional context
A safer implementation would ensure the refresh token is read dynamically rather than relying on a value captured during render.
Proposed Fix 1: Dynamic Lookup
queryFn: () => {
const refreshToken = localStorage.getItem("care_refresh_token");
return authApi.refresh({ refresh: refreshToken });
}Proposed Fix 2: Reactive Query Key
Include the refresh token in the query key to ensure React Query recreates the query when the token changes:
queryKey: ["user-refresh-token", refreshToken]I would be happy to work on implementing a fix for this issue if maintainers confirm the preferred approach.
🚨 DO NOT EDIT BELOW THIS LINE 🚨
Instructions for Requesting Assignment:
To request assignment, please clearly outline your solution and timeline by commenting on the issue using the format below:
Describe your solution clearly:
Provide a detailed explanation of your proposed solution, including your approach, key implementation steps, and relevant examples or references. Mention any dependencies, assumptions, or risks you foresee that might affect your timeline or implementation.
Expected Timeline:
- End date: [Expected submission date of a completed Pull Request]
Additional Context:
Include any other relevant context, links, screenshots, or resources that support your proposed solution.
🚨 Your assignment may be unassigned if there is no activity or progress within the stated timeline unless communicated clearly and agreed upon.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status