JWT Access Token vs Refresh Token Patterns

JWT access token and refresh token patterns: lifetimes, storage, rotation, revocation. Decode your access token above to read its exp and claims.

ZERO UPLOAD · ALL LOCAL
  1. Copy your JWT token — it looks like three Base64 sections separated by dots (eyJ…)
  2. Paste the token into the input field — decoding happens automatically on paste.
  3. Read the Header panel: it shows the signing algorithm (alg) and token type (typ).
  4. Read the Payload panel: it shows all claims — user ID, roles, issued-at (iat), and expiry (exp).
  5. Check the expiry status indicator — it shows whether the token is currently valid or expired, with a human-readable time delta.
  6. Note: the tool decodes only — it does not verify the signature. Never trust decoded claims in a security context without server-side verification.

What to look for

  • 5-60 minutes
  • hours to days

Decode your access token above to confirm its exp before assuming a refresh failure is the cause of a 401.

HEADER
          
PAYLOAD
          
EXPIRY

JWT Access Token vs Refresh Token Patterns

In JWT authentication, access tokens and refresh tokens serve different purposes. An access token is short-lived (5–60 minutes), sent with every API request, and carries the user identity and permissions the server needs for authorisation.1 A refresh token is long-lived (hours to days), stored securely, and used only to obtain a new access token when the old one expires. Paste any access token above to read its exp and claims without sending it to a third party.

The separation of lifetimes is deliberate. Short-lived access tokens limit the damage from token theft: a stolen token becomes useless in minutes without a corresponding refresh token. Refresh tokens stored in HttpOnly cookies are inaccessible to JavaScript and therefore protected from XSS attacks, while access tokens kept in memory (not localStorage) have no persistent cross-origin exposure. Understanding both token types prevents the common mistake of storing access tokens in localStorage where browser scripts can read them.

Access token lifecycle

Access tokens carry everything your API needs to process a request: user ID in sub, permissions in scope or roles, and an expiry in exp. Your API verifies the signature and reads claims on every request without a database lookup: this is the stateless authentication benefit of JWTs. Short lifetimes (5-15 minutes for sensitive APIs, up to 60 minutes for lower-risk endpoints) minimise exposure time if a token is intercepted. Consequently, clients must refresh access tokens frequently, which is handled transparently by the auth SDK without user interaction.

Reading access-token claims before refresh

Decode the access token first when a request fails: the exp, scope, and role claims often reveal whether the client sent the right token or whether the backend expected different permissions. A token with an expired exp but valid signature means the client simply needs to refresh, while a token with the wrong scope or audience indicates a configuration issue on the client side that no amount of refreshing will resolve.

Refresh token lifecycle

Refresh tokens are opaque strings that are not JWTs and cannot be decoded because the authorization server alone maintains the mapping between the opaque value and the associated user session. They serve as long-lived credentials exchanged at the token endpoint for a new access and refresh token pair, and their opacity is intentional: unlike JWTs, nothing in the token itself reveals user identity or permissions. Token rotation, which issues a new refresh token on every exchange and invalidates the old one, detects token theft because if an attacker uses the refresh token before the legitimate client does, the legitimate client's next refresh attempt fails and triggers a re-authentication flow.1 Most providers implement a refresh token reuse detection window that flags suspicious simultaneous refresh attempts for additional security.

Storage and security

Store access tokens in memory using a JavaScript variable or React state so they disappear on page reload and are never accessible to browser extensions or scripts running in other tabs, which substantially reduces the attack surface compared to persistent storage mechanisms.2 Store refresh tokens in HttpOnly, Secure, SameSite=Strict cookies to prevent XSS from reading them and CSRF from sending them cross-origin, ensuring that only the intended token endpoint can receive the refresh credential. Never store either token type in localStorage or sessionStorage because these are accessible to any script on the page, including third-party analytics or injected code, and the auth SDK you choose should manage token storage automatically according to this in-memory-plus-cookie pattern.

Silent token refresh with PKCE in single-page applications

Silent token refresh in a single-page application uses the auth provider's session cookie to obtain a new access token without user interaction. When the SPA detects the access token is near expiry (typically within 60 seconds of exp), it triggers a background refresh call to the authorization server. The server validates the session cookie, issues a new access token, and returns it to the SPA. The user sees no interruption.

How PKCE protects public clients

PKCE (Proof Key for Code Exchange) protects the refresh flow in SPAs that cannot store client secrets.3 The SPA generates a random code_verifier, hashes it to produce code_challenge, and includes code_challenge in the initial authorization request. On token exchange, it sends the original code_verifier; the server hashes it and compares. No shared secret is needed, making PKCE the standard for public clients where a network observer could otherwise intercept the authorization code.

Handling refresh failures and cookie restrictions

When refresh fails, inspect whether the provider session cookie still exists and whether the browser blocked the background request as third-party tracking. Some embedded or privacy-focused contexts restrict cross-site cookies, so the SPA may need to redirect through the provider instead of relying on a hidden iframe. Keep the PKCE verifier in memory, discard it after exchange, and generate a fresh verifier for the next authorization attempt.

A background refresh that fails silently is the hardest case to diagnose, so surface the failure with a clear client event rather than swallowing the error. When a silent refresh fails, causes of silent-refresh JWT failure should be your first check before assuming the refresh flow itself is broken. Privacy browsers and embedded web views frequently block the cookie or the cross-site request that the silent flow depends on. Designing the fallback to redirect through the provider keeps the session alive when the hidden iframe approach is unavailable.

When to use this

Implement this token pattern in any web or mobile application that uses JWT-based authentication: it is the standard pattern for all OAuth 2.0 and OIDC flows regardless of the identity provider. When a silent refresh fails, run the access token through the decoder first to rule out a simple expired-token case before assuming the refresh flow itself is broken.

Examples

Access token read in a React component (in-memory storage)

Before
// Access token in memory (React state, not localStorage)
const { accessToken } = useAuth();

// Send with every API request
fetch("/api/data", {
  headers: {
    Authorization: `Bearer ${accessToken}`
  }
});

In-memory tokens disappear on page reload. The auth SDK silently refreshes using the HttpOnly cookie before expiry.

Token rotation: refresh endpoint pattern

Before
// Refresh endpoint returns both tokens
POST /auth/refresh
Cookie: refresh_token=<opaque-string>

// Response
{
  "access_token": "eyJ...",
  "expires_in": 900
  // new refresh_token set in HttpOnly cookie
}

The new refresh token replaces the old one. The old token is immediately invalidated to prevent replay.

Sources
  1. 1.

    T. Lodderstedt, J. Bradley, A. Labunets, and D. Fett, "Best Current Practice for OAuth 2.0 Security," RFC 9700, IETF, February 2025. https://www.rfc-editor.org/rfc/rfc9700

  2. 2.

    OWASP, "Session Management Cheat Sheet," owasp.org, accessed June 2026. https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html

  3. 3.

    N. Sakimura, Ed., J. Bradley, and N. Agarwal, "Proof Key for Code Exchange by OAuth Public Clients," RFC 7636, IETF, September 2015. https://www.rfc-editor.org/rfc/rfc7636

FAQ