JWT Refresh Token Rotation Best Practices for Web APIs
Quick answer
Refresh token rotation means issuing a new refresh token every time one is used and invalidating the old one. Combined with short-lived access tokens, it...
Refresh token rotation means issuing a new refresh token every time one is used and invalidating the old one. Combined with short-lived access tokens, it limits how long a stolen token is useful and lets the server detect token theft through reuse. The best practices are storing refresh tokens server-side as hashes, detecting reuse, revoking token families, and delivering tokens through secure channels.
Why Use Short-Lived Access Tokens and Refresh Tokens?
A JWT access token is typically validated without a database lookup, which makes it fast but hard to revoke. If it is valid for hours or days, a stolen token gives an attacker that long to act. Short lifetimes, often minutes, reduce that window.
Short access tokens would force users to log in constantly, so a refresh token is used to obtain new access tokens quietly. The refresh token lives longer, so it deserves stricter protection and server-side control. Unlike the access token, it is sent only to the token endpoint, which reduces its exposure.
The security of the design rests on the refresh token, which is why rotation matters. A static refresh token that never changes is a long-lived credential waiting to be stolen.
How Does Refresh Token Rotation Work?
Each time the client exchanges a refresh token, the server returns a new access token and a new refresh token, and marks the old refresh token as used. If someone presents an already used token, something is wrong: either the legitimate client or an attacker has a stale copy.
- Store each refresh token's identifier or hash, its owner, its expiry, and a family identifier linking tokens from the same login.
- On use, verify the token, mark it consumed, and issue a replacement in the same family.
- On reuse of a consumed token, revoke the whole family and require the user to authenticate again.
- Apply both an idle timeout and an absolute lifetime, so sessions cannot extend forever.
Reuse detection is the main benefit. If an attacker uses a stolen token first, the legitimate client's next refresh fails and triggers revocation. If the legitimate client refreshes first, the attacker's copy becomes useless.
What Are the Common Implementation Pitfalls?
Network failures cause trouble. If the server rotates a token but the response is lost, the client still holds the old one, and its retry looks like reuse. Some systems add a short grace period for the most recent token, or make the exchange idempotent for a brief window. Weigh this carefully, because a grace period slightly weakens reuse detection.
Concurrency is another source of bugs. Web and mobile apps may fire several requests that all find the access token expired and attempt refreshes at the same time. Serialize refresh calls on the client, so only one runs and the others wait for its result.
Finally, avoid storing raw refresh tokens in your database. Store a hash, as you would with a password reset token, so a database leak does not hand over working credentials. Use long random values rather than structured tokens for refresh tokens, unless you have a specific reason otherwise.
How Should Tokens Be Stored and Delivered?
For browser applications, delivering the refresh token in a cookie with the HttpOnly, Secure, and SameSite attributes keeps it out of reach of JavaScript, which reduces the impact of cross-site scripting. Pair this with CSRF protection on the refresh endpoint. For mobile apps, use platform secure storage, such as the Keychain or Keystore.
Always use HTTPS, avoid putting tokens in URLs, and never log them. Follow current guidance from the OAuth working group and your identity provider, since recommendations for browser-based apps continue to evolve.
Frequently Asked Questions
How long should an access token live?
Commonly 5 to 15 minutes. Choose a lifetime based on risk and how quickly you need changes in permissions to take effect.
Should refresh tokens be JWTs?
Not necessarily. Opaque random tokens tracked on the server are simpler and easier to revoke, since you must store state for rotation anyway.
What happens if a refresh token is reused?
Treat it as a possible theft. Revoke the token family and require reauthentication.
Can I revoke an access token immediately?
Not with pure stateless validation. Keep lifetimes short, or maintain a denylist for high-risk cases.
Summary
Use short-lived access tokens, rotate refresh tokens on every use, detect reuse, and revoke families when it happens. Store hashes, protect delivery channels, and handle retries and concurrency. Consult current OAuth and identity provider documentation for details.