{Inspector}

Security guide

JWT Refresh Tokens Explained: Expiration, Rotation & Security

A JWT access token is stateless, which makes it both convenient and risky: nothing on the server remembers it, so a stolen token works until it expires. Refresh tokens are the standard fix — a short-lived access JWT backed by a long-lived credential that is rotated on every use. Here is how the lifetimes, rotation and reuse detection actually work in production auth.

Benjamin Rotshtein

Written by Benjamin Rotshtein

Updated

What is a refresh token for?
To mint new short-lived access tokens without asking the user to log in again — convenience with a tiny blast radius.
How long should it live?
7–30 days is the mainstream default, often with sliding expiration so active users never notice.
Why rotate it?
Every refresh invalidates the old token, so a stolen one stops working the moment it is used, and reuse detection revokes the whole family.

How do JWT refresh tokens keep users logged in?

When a short-lived access token expires, the client presents the refresh token at the token endpoint and receives a fresh access token — and usually a rotated refresh token too. The refresh token lives only in the browser’s secure storage and never travels with API calls, so a stolen access token stops mattering within minutes.

Why access JWTs must be short-lived

A JWT carries its own identity and can be verified by any service holding the signing key. There is no server record to check, so a leaked access token is fully valid until the exp claim. The defense is a short lifetime: keep the access token at 5–15 minutes so an attacker's window is minutes, not weeks. The refresh token then supplies the convenience without widening that window.

To inspect a token's actual claims — expiry, issuer, audience — paste it into the JWT Decoder. It runs entirely in your browser, so the payload never leaves your machine.

The three-token lifecycle

CredentialLifetimeWhere it goesIf stolen
Access token (JWT)5–15 minutesEvery API requestWorks until expiry — short window
Refresh token7–30 days (rolling ok)Token endpoint onlyNeutralized by rotation + reuse detection
Session recordLife of the refresh tokenServer-side, never to clientRevoked by deleting the record

Refresh token rotation and reuse detection

Rotation means each token exchange mints a new refresh token and invalidates the old one. The normal flow looks like this:

POST /token  { grant_type: "refresh_token", refresh_token: "R1" }
  -> 200 { access_token: "A2", refresh_token: "R2" }   # R1 now dead

# Attacker replaying R1 after it was rotated:
POST /token  { grant_type: "refresh_token", refresh_token: "R1" }
  -> 401, AND the server flags R1 as already used

Reuse detection is the rule that turns a replay into an alarm: if a rotated-out refresh token is ever presented again, treat the entire token family as compromised. Revoke every token issued from that family and force a fresh login. This is what stops an attacker who stole a token from quietly staying logged in.

Where to store each token

Expiration: short expiry vs sliding

Two patterns dominate. Fixed expiry (e.g. 30 days) logs everyone out on a schedule and is simplest to reason about. Sliding expiration extends the refresh token's life each time it is used, so active users stay logged in indefinitely while idle sessions expire on their own. Sliding fits subscription products; fixed fits anything with compliance limits. Keep the exp claim on the access JWT strictly enforced on the server — trusting the client is how expired tokens slip through.

Ready to inspect a real token?

Frequently asked questions

What is a JWT refresh token?

A refresh token is a long-lived credential exchanged for new short-lived access tokens. The access JWT lives 5–15 minutes and is sent with every request; the refresh token is stored securely and only sent to the token endpoint to mint the next access token. This keeps the token you actually expose to every API short-lived, so a leak has a tiny blast radius.

How long should a refresh token live?

Common production lifetimes are 7 to 30 days, often with sliding expiration — the refresh token is renewed when it is used, so active users never log out and inactive sessions expire. Some apps persist a valid session for months with rolling refresh, but that trades security for convenience; 7–30 days with rotation is the mainstream default.

Why do access tokens expire in 5–15 minutes?

Because they are stateless. A stolen access token works until it expires, and shortening the lifetime shrinks the window an attacker can abuse it. 5–15 minutes is short enough to limit damage, long enough to avoid hammering the token endpoint on every API call. The refresh token adds the convenience of never re-authenticating.

What is refresh token rotation and reuse detection?

Rotation means every time a refresh token is used to mint a new one, the old token is invalidated, so stolen tokens go stale quickly. Reuse detection means if a rotated-out refresh token is ever presented again, you treat it as a compromise: revoke the whole family and force re-login. Together they stop both token theft and replay attacks.

Where should I store a JWT access and refresh token?

Access tokens commonly live in memory (kept in JavaScript state) to dodge XSS exfiltration; refresh tokens should live in an httpOnly, Secure, SameSite cookie so browser scripts cannot read them, or in secure storage for mobile/native apps. Avoid localStorage for refresh tokens — any XSS can steal them, and they are the keys to the kingdom.

Related guides