What Is Refresh Token Rotation?
Learn how refresh token rotation works, why single-use tokens detect theft, and how token family revocation limits damage.
Expected Interview Answer
Refresh token rotation is a security pattern where every time a refresh token is used to obtain a new access token, the server also issues a brand-new refresh token and immediately invalidates the old one, so each refresh token is single-use.
Instead of a long-lived refresh token staying valid for weeks and being reused on every silent re-auth, rotation swaps it out on each exchange: the client sends refresh token A, the server verifies it, issues a fresh access token plus a new refresh token B, and marks A as consumed. If A is ever presented again after B has already been issued, the server treats that as a signal of theft โ because a legitimate client would only ever use the latest token โ and can revoke the entire token family, forcing re-login. This turns a stolen, static refresh token into a one-time-use liability rather than a standing backdoor. Implementations track a token family with a shared identifier so revoking one compromised branch invalidates all descendants, and they persist rotation state server-side (or in a signed, chained JWT claim) so reuse detection actually works across distributed servers.
- Limits the blast radius of a stolen refresh token to one exchange
- Enables automatic theft detection via reuse-of-a-consumed-token signal
- Keeps access tokens short-lived without forcing constant full re-logins
- Supports revoking an entire compromised token family at once
AI Mentor Explanation
Refresh token rotation is like a stadium issuing a fresh single-entry re-entry stub every time you leave and come back, instead of one stub good for the whole match. The gate destroys your old stub the moment it hands you the new one. If someone ever tries to use a stub that has already been swapped for a newer one, security knows immediately that two people are holding copies and locks the whole ticket down. That single-use, swap-and-invalidate cycle is exactly how refresh token rotation catches theft.
Step-by-Step Explanation
Step 1
Client exchanges refresh token
The client sends its current refresh token to the auth server to request a new access token.
Step 2
Server issues new pair, invalidates old
The server validates the token, issues a new access token and a new refresh token, and marks the old refresh token as consumed.
Step 3
Reuse detection on replay
If the now-consumed refresh token is ever presented again, the server treats it as a theft signal.
Step 4
Revoke the whole token family
On detected reuse, the server invalidates every token descended from that family, forcing a full re-login.
What Interviewer Expects
- Clear explanation of single-use refresh tokens and why they rotate
- Understanding of reuse detection as a theft signal, not just an error
- Awareness of token families and family-wide revocation
- Knowledge that this pairs with short-lived access tokens for defense in depth
Common Mistakes
- Confusing rotation with simply extending refresh token expiry
- Not explaining what happens when a consumed token is replayed
- Forgetting that rotation requires server-side persisted state to detect reuse
- Assuming rotation alone replaces the need for short-lived access tokens
Best Answer (HR Friendly)
โRefresh token rotation means every time your app quietly renews its login session, it gets a brand-new refresh token and the old one stops working immediately. If that old, already-replaced token ever gets used again, the system knows something is wrong โ like someone stole a copy โ and it can shut down that whole session chain to protect the account.โ
Code Example
async function refreshSession(oldRefreshToken) {
const record = await db.refreshTokens.findByToken(oldRefreshToken)
if (!record || record.revoked) {
// Token already consumed or unknown: possible theft, kill the family
if (record) await db.refreshTokens.revokeFamily(record.familyId)
throw new Error('Refresh token reuse detected')
}
await db.refreshTokens.revoke(record.id)
const newRefreshToken = generateToken()
await db.refreshTokens.create({
token: newRefreshToken,
familyId: record.familyId,
parentId: record.id,
})
const accessToken = signAccessToken({ userId: record.userId })
return { accessToken, refreshToken: newRefreshToken }
}Follow-up Questions
- How would you store refresh tokens server-side to make reuse detection reliable across multiple servers?
- What is a token family and why does revoking it matter?
- How does refresh token rotation interact with short-lived access token expiry?
- What are the tradeoffs of rotating tokens on every request versus a fixed rotation interval?
MCQ Practice
1. What is the defining property of a rotated refresh token?
Rotation makes each refresh token usable exactly once before being replaced and invalidated.
2. What does it mean if a server sees a previously-consumed refresh token used again?
Because tokens are single-use, replaying a consumed one strongly suggests a copy was stolen.
3. What should happen when refresh token reuse is detected?
Revoking the whole family shuts down every descendant token derived from the compromised chain.
Flash Cards
What is refresh token rotation? โ Issuing a new refresh token and invalidating the old one on every use.
What signals theft in rotation? โ A previously-consumed refresh token being presented again.
What is a token family? โ A chain of refresh tokens descended from one original login, revocable together.
Why pair rotation with short-lived access tokens? โ Rotation limits refresh token misuse; short access token life limits stolen-access-token misuse.