flashman
← All posts

JWT refresh token rotation: debug stale sessions and 401s

Debug JWT refresh token rotation bugs by decoding access tokens, checking expiry windows, comparing stored state, and avoiding unsafe production token sharing.

2026-07-03 · 6 min read · Rahul Chitturi

  • jwt
  • auth
  • debugging

Refresh token rotation is designed to reduce replay risk, but it can make session bugs harder to diagnose. One tab refreshes successfully while another keeps an old token. A mobile app retries with stale state. A backend revokes the family after detecting reuse.

The safest debugging path is to inspect non-production tokens, compare expiry windows, and trace state transitions without weakening verifier rules.

Decode the access token first

The access token usually tells you which session, tenant, audience, and expiry the API saw. Decode it as data, not as proof of trust. Look for exp, iat, nbf, iss, aud, sub, scope, and any session identifier your identity provider adds.

  • exp shows when the access token should stop working
  • iat helps identify whether the client used a fresh or stale token
  • sid or jti can tie requests to a refresh token family
  • scope differences can explain 403 responses that look like auth failures

Map the rotation timeline

Convert token timestamps to human time and line them up with client logs. If two refresh requests happen close together, the second may reuse a token that was already rotated. This commonly appears after page reloads, background mobile resumes, or retry loops around flaky networks.

Compare stored client state

When a bug affects one browser profile or device, compare the stored auth state before and after refresh. The stale value may be in memory, local storage, an HTTP-only cookie, or a service worker cache. Diff redacted snapshots so reviewers can see whether the token family, expiry, or selected tenant changed.

A Flashman workflow

Decode test access tokens with the JWT tool, convert exp and iat with the timestamp converter, and format redacted auth-state JSON before comparing snapshots. Never paste live production refresh tokens into tickets or third-party tools; create a synthetic reproduction when you need to share details.

Try these tools