Context
The auth API rotates refresh tokens and detects reuse. On reuse it does not just reject
the replayed token, it revokes the whole session chain, including the access token issued
by the legitimate rotation. A spike confirmed this: replaying a spent token returned
401 refresh_token_reused, and the previously working access token immediately began
returning 401.
That behaviour is correct, and it makes a client side guard mandatory rather than nice to
have. On mobile several screens can mount at once and race a refresh. Two concurrent
refreshes mean one of them replays a spent token, which signs the user out.
Scope
- Ensure at most one refresh is in flight; concurrent callers await the same promise.
- Callers that arrive during a refresh must receive the refreshed token, not trigger
another rotation.
- Cover the race in tests, since it will not reproduce reliably by hand.
Notes
Applies to the web binding too. The web SDK is less exposed because the BFF holds the
refresh token, but the shared client should own the guard.
Context
The auth API rotates refresh tokens and detects reuse. On reuse it does not just reject
the replayed token, it revokes the whole session chain, including the access token issued
by the legitimate rotation. A spike confirmed this: replaying a spent token returned
401 refresh_token_reused, and the previously working access token immediately beganreturning 401.
That behaviour is correct, and it makes a client side guard mandatory rather than nice to
have. On mobile several screens can mount at once and race a refresh. Two concurrent
refreshes mean one of them replays a spent token, which signs the user out.
Scope
another rotation.
Notes
Applies to the web binding too. The web SDK is less exposed because the BFF holds the
refresh token, but the shared client should own the guard.