Refresh flow
Access tokens expire quickly. Refresh tokens rotate and are tracked per session in Redis to reject replay and concurrent reuse.
const nextTokens = await auth.refreshToken(currentRefreshToken);
The rotation sequence is:
- Verify the refresh token's signature, issuer, audience, expiry, and
refreshpurpose. - Require
userId,email, andsessionIdclaims. - Acquire the session's namespaced, digest-keyed lock in Redis.
- Compare the submitted token with its namespaced, digest-keyed refresh record.
- Atomically replace the stored value with the newly signed refresh token.
- Issue a new access token for the same session.
- Release the lock.
Reusing an old token fails. A competing refresh attempt also fails closed.
await auth.refreshToken(currentRefreshToken); // succeeds
await auth.refreshToken(currentRefreshToken); // rejects the replay
Store the returned token
After a successful refresh, replace the previous refresh token with the returned value. The previous token is no longer valid.
Generated fullstack applications store the refresh token in a restricted HttpOnly cookie and keep access tokens in browser memory. Express API presets return both values in JSON so the API client can choose an appropriate secure storage boundary.