100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Programming

The Refresh Token Grant

Refresh tokens let a client obtain new access tokens without repeating the full authorization flow, keeping short-lived access tokens practical for long-running sessions.

Grant TypesIntermediate9 min readJul 10, 2026
Analogies

Why Refresh Tokens Exist

Access tokens are deliberately short-lived, often 5 to 60 minutes, so that if one leaks, the exposure window is small. But making a user log in again every hour would be unusable. Refresh tokens solve this: issued alongside the access token (typically only for Authorization Code and Device Code flows), a refresh token is a longer-lived credential the client can present to /token with grant_type=refresh_token to obtain a fresh access token, and often a fresh refresh token too, without the user seeing another login screen.

🏏

Cricket analogy: It's like a season ticket at a cricket ground: your matchday entry pass (the access token) expires after each game, but the season ticket itself (the refresh token) lets you print a new matchday pass for the next fixture without re-registering.

Rotation and Reuse Detection

Modern best practice is refresh token rotation: every time a refresh token is used, the server invalidates it and issues a brand new refresh token alongside the new access token, so each refresh token is single-use. This lets the server detect theft: if an old, already-used refresh token is ever presented again, that's a strong signal the token was stolen and used by an attacker in parallel with the legitimate client, and the server should immediately revoke the entire token family, forcing re-authentication for everyone holding a token from that lineage.

🏏

Cricket analogy: It's like a stadium requiring each entry wristband to be cut off and replaced with a new one at every re-entry; if security ever sees someone try to reuse a wristband already marked 'cut', it's proof of a forged duplicate and the whole gate's access is locked down.

Storage and Lifetime Policy

Refresh tokens are the most sensitive artifact in an OAuth deployment because they often live for days, weeks, or indefinitely (until revoked), unlike short-lived access tokens. For confidential clients, they should be stored server-side, never in browser localStorage or a mobile app's plain shared preferences; for SPAs, the recommended pattern is a backend-for-frontend (BFF) that holds the refresh token server-side and only ever hands the browser a short-lived, httpOnly session cookie. Authorization servers typically also enforce an absolute lifetime (say, 30 or 90 days) alongside the rolling per-use expiry, so a token can't be kept alive forever purely through automated refresh activity.

🏏

Cricket analogy: It's like a franchise storing a player's multi-year central contract documents in a locked HR vault rather than handing the physical contract to the player to carry around, only ever giving the player a daily access badge derived from it.

http
POST /oauth/token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=v1.MzY4YzQ4NzYtOTFhZS00...
&client_id=mobile-app-789

# Response — note the rotated refresh_token
HTTP/1.1 200 OK
Content-Type: application/json

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "v1.NDIxYzU5ODctODJiZi01...",
  "scope": "orders:read orders:write"
}

# If the OLD refresh_token above is ever replayed after this point,
# the server should revoke the entire token family:
HTTP/1.1 400 Bad Request
{ "error": "invalid_grant", "error_description": "token reuse detected" }

The refresh_token grant is only issued for flows that had a genuine resource owner and consent step — chiefly Authorization Code (with or without PKCE) and Device Code. Client Credentials never gets one, because the client can simply re-authenticate with its own secret whenever it needs a new access token.

Common Refresh Token Mistakes

The most frequent production mistake is treating a non-rotating, long-lived refresh token as safe to store in browser localStorage; localStorage is readable by any JavaScript running on the page, so a single XSS vulnerability anywhere in the app hands an attacker a token that can mint fresh access tokens indefinitely. A second common mistake is failing to implement reuse detection at all, silently accepting any valid refresh token forever, which means a leaked token from months ago, say, from an old log file, still works and nobody is alerted when it's used.

🏏

Cricket analogy: It's like leaving the pavilion's master key under the doormat because it's convenient; anyone who finds it, not just the groundskeeper, can let themselves in indefinitely with no alarm ever triggered.

Never store a refresh token in browser localStorage or sessionStorage for a public client (SPA). Both are trivially readable by any script on the page, so a single XSS bug becomes a permanent account takeover. Use the backend-for-frontend pattern: the refresh token stays server-side, and the browser only ever holds a short-lived httpOnly, SameSite cookie.

  • Refresh tokens let clients obtain new access tokens without repeating the full user-facing authorization flow.
  • Only user-facing flows (Authorization Code, Device Code) issue refresh tokens; Client Credentials does not.
  • Rotation issues a brand new refresh token on every use and invalidates the old one, making each refresh token single-use.
  • Reuse of an already-rotated refresh token is a strong theft signal and should trigger revocation of the entire token family.
  • Refresh tokens must never be stored in browser localStorage for public clients; use server-side storage via a backend-for-frontend.
  • Authorization servers typically enforce both a rolling expiry (per use) and an absolute maximum lifetime for refresh tokens.
  • Failing to implement reuse detection means a leaked refresh token from the past can still be used silently, with no alert.

Practice what you learned

Was this page helpful?

Topics covered

#Programming#OAuth20StudyNotes#TheRefreshTokenGrant#Refresh#Token#Grant#Tokens#StudyNotes#SkillVeris#ExamPrep