This guide is written by the team that builds Casdoor and describes the standards as published (listed under Sources), with notes on how Casdoor implements them as of November 1, 2026. Spotted a mistake? Tell us.
Short-lived access tokens are good security: a leaked token stops working in minutes. The price is that clients need a way to renew them without asking the user to sign in again. That is the refresh token — and it is the most valuable credential in the system.
Rotation is the practice of issuing a new refresh token every time the old one is used, and invalidating the old one.
Why rotate
A refresh token is long-lived by design. If it leaks, an attacker can mint access tokens for as long as it lives. Rotation reduces the blast radius:
- A stolen refresh token is only useful until the legitimate client uses its own — which invalidates it.
- When the stolen token is used after being replaced, the server sees a reuse and can revoke the entire token family.
- Short refresh-token lifetimes become practical, because the client renews them on every use.
The threat model is spelled out in RFC 6819: bearer tokens must be protected in storage and in transit, and stolen tokens must be detectable where possible.
How it works
- The client exchanges a refresh token for a new access token.
- The server issues a new refresh token in the same response.
- The old refresh token is marked as used and can no longer be redeemed.
- If a used refresh token is presented again, the server treats it as a compromise: it revokes the token family and forces a new login.
The "family" is the chain of tokens descended from one original grant. Revoking the family is what turns a silent theft into a visible event.
What OAuth 2.1 expects
The OAuth 2.1 draft consolidates the specs and tightens the rules for public clients: a client that cannot keep a secret should either rotate refresh tokens or use sender-constrained tokens. The old pattern — a long-lived static refresh token in a public client — is what the draft is trying to retire.
Sender-constrained options:
- DPoP (RFC 9449): the client proves possession of a key with each request; a stolen token is useless without the key.
- mTLS (RFC 8705): the token is bound to a client certificate.
Most teams start with rotation; DPoP and mTLS are for high-security deployments.
Implementation checklist
- Store refresh tokens hashed, not in plaintext. A database leak should not hand out sessions.
- One active refresh token per session. Keep the family ID so you can revoke all descendants.
- Mark tokens as used atomically. Two concurrent refreshes must not both succeed.
- Revoke the family on reuse. Log the event; it is a security signal, not a bug.
- Set an absolute lifetime in addition to the rotation lifetime, so a session cannot live forever.
- Revoke on logout, password change, MFA change and admin action.
- Cap tokens per user and show a device list where it makes sense.
- Rotate on privilege change — a new role is a new authorization context.
The concurrency trap
Rotation breaks naive clients. Consider a mobile app that fires five API calls, each detecting an expired access token and refreshing independently:
- All five send the same refresh token.
- The first succeeds and invalidates it.
- The other four look like reuse.
- The server revokes the family, and the user is logged out.
Fixes:
- Serialize refresh in the client: one refresh at a time, queue the rest.
- Add a short grace window on the server: accept the previous token for a few seconds after rotation, but never twice.
- Coordinate across tabs with a lock (for example, a storage-based mutex or a service worker).
The grace window is a trade-off: too long and it weakens reuse detection; too short and legitimate clients get logged out. Minutes of grace are almost never acceptable; seconds can be.
What a good server response looks like
- Rotation on every use.
- A new refresh token in every refresh response.
- Reuse detection with family revocation and an audit event.
- Revocation endpoints that actually revoke, including access tokens where the architecture allows.
- Refresh-token expiry surfaced to the client, so it can re-authenticate proactively.
Casdoor implements OIDC refresh tokens and supports refresh-token rotation for applications, which is what makes short access-token lifetimes practical. See the session and token docs.
Related reading: where to store a JWT, OAuth grant types and what OAuth 2.0 is.
Sources
- RFC 6749: The OAuth 2.0 Authorization Framework (refresh tokens)
- RFC 6819: OAuth 2.0 Threat Model and Security Considerations
- RFC 9449: OAuth 2.0 Demonstrating Proof of Possession (DPoP)
- RFC 8705: Mutual-TLS Client Authentication
- OAuth 2.1 draft
Product names are trademarks of their respective owners.