Hint
Each refresh issues a new refresh token and invalidates the old one — if a stolen token is used, the legitimate session is detectable
The problem: Access tokens are short-lived (15 min), but refresh tokens are long-lived (days/weeks). A stolen refresh token gives an attacker indefinite access.
Refresh token rotation:
// Token family concept
POST /auth/refresh { refreshToken: "rt_v1" }
→ { accessToken: "at_new", refreshToken: "rt_v2" }
// rt_v1 is now invalid
// If attacker uses rt_v1 again:
POST /auth/refresh { refreshToken: "rt_v1" }
→ 401 — AND server invalidates rt_v2 too (reuse detected)
Storage: Refresh tokens should be stored in HttpOnly cookies, never localStorage.