Skip to main content

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:

  1. Verify the refresh token's signature, issuer, audience, expiry, and refresh purpose.
  2. Require userId, email, and sessionId claims.
  3. Acquire the session's namespaced, digest-keyed lock in Redis.
  4. Compare the submitted token with its namespaced, digest-keyed refresh record.
  5. Atomically replace the stored value with the newly signed refresh token.
  6. Issue a new access token for the same session.
  7. 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.