🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Refresh Tokens

Implementing short-lived access tokens paired with refresh tokens for secure, low-friction session management.

Total XP: 0|💻 backend XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

Select an unlocked node to view details root

🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

1Step-by-Step Breakdown

The Core Tradeoff a Single Long-Lived Token Forces. A single JWT with a long expiration (say, 30 days) minimizes login friction but maximizes damage if stolen — it remains valid for the attacker for the full 30 days. A short expiration (5 minutes) minimizes stolen-token damage but forces the user to re-login constantly. Refresh tokens resolve this tradeoff.

The Two-Token Model. A short-lived "access token" (minutes) authorizes actual API requests, while a longer-lived "refresh token" (days/weeks) has exactly one purpose: exchanging itself for a new access token when the current one expires — the access token's short life limits stolen-token exposure; the refresh token minimizes how often the user re-authenticates.

Implementing the Refresh Endpoint. A dedicated /auth/refresh endpoint accepts a valid refresh token and issues a brand-new access token (and often a new refresh token too, covered in Token Rotation) — this endpoint is the ONLY place a refresh token is ever used, never sent alongside regular API requests.

Storing Refresh Tokens Server-Side for Revocation. Unlike a stateless access token, a refresh token's validity should be checkable and revocable server-side (stored in a database, associated with the specific user and device) — this is what makes "log out this device" or "revoke all sessions after a suspected compromise" actually possible, which a purely stateless token cannot support.

Where Each Token Should Live in the Client. An access token can reasonably live in memory (JavaScript variable, lost on page refresh, refetched via the refresh token) since its short life limits exposure risk. A refresh token, being longer-lived and higher-value, belongs in an HttpOnly cookie (covered in Secure Cookies) — never in localStorage, which is readable by any XSS payload.

Handling Refresh Failure Gracefully on the Client. A client-side HTTP interceptor that automatically attempts a token refresh when an API call returns 401 (access token expired), retrying the original request with the new token, provides a seamless experience — the user never notices their access token expired, as long as their refresh token remains valid.

The Refresh Token's Own Expiration and Re-Login. Even a refresh token eventually expires — at that point, the user genuinely must re-authenticate with credentials, which is the deliberate, acceptable tradeoff: a refresh token's expiration (days/weeks) balances security (bounding the absolute maximum session length) against convenience (far less frequent than the access token's own expiration).

Why should a refresh token be stored in an HttpOnly cookie rather than localStorage, given that an access token is often kept in memory instead?

  • A refresh token is longer-lived and higher-value, and localStorage is readable by any XSS payload — HttpOnly blocks that access
  • localStorage has a size limit too small to store a refresh token

Level Up 🚀

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

Fully supported.

Accessibility (A11y)

1Seamless Token Refresh Prevents Unexpected Session Interruptions Mid-Task

A transparent client-side refresh mechanism prevents a user from being unexpectedly logged out mid-task simply because their access token expired — an interruption that would be especially disruptive for a user relying on assistive technology who may have invested significant extra time completing a long, multi-step form.

SEO Implications

  • 1

    Revocable Refresh Tokens Enable Fast Incident Response to a Compromised Account

    Server-side revocable refresh tokens allow immediate session termination in response to a suspected account compromise or security incident, meaningfully reducing the duration and impact of the incident, which directly affects the severity of any resulting trust and reliability damage.

Best Practices

Use a short-lived access token for regular API requests, paired with a longer-lived, server-side revocable refresh token

This resolves the tradeoff a single token forces between minimizing stolen-token exposure and minimizing login friction, giving you both properties simultaneously.

Store the refresh token in an HttpOnly, Secure cookie, never in localStorage

The refresh token is the higher-value, longer-lived credential — localStorage is readable by any XSS payload, while HttpOnly blocks JavaScript access entirely.

Frequent Bugs

THE BUG

After a user reports their account was compromised, the security team has no way to immediately terminate that user's active sessions across all their devices.

THE FIX

This points to refresh tokens being issued as purely stateless tokens with no server-side record, making revocation impossible before natural expiration. Persist issued refresh tokens server-side (associated with the user and device) so they can be explicitly revoked in response to an incident.

Real-World Examples

Enabling Fast Incident Response Through Revocable Refresh Tokens

A user reported their laptop was stolen while still logged into the company's application. Because refresh tokens were stored server-side per device, the support team was able to immediately revoke that specific device's refresh token, forcing it to fail on its next refresh attempt and requiring full re-authentication — while the user's other, trusted devices remained unaffected. Without server-side revocation, the stolen laptop's session would have remained valid until the refresh token's natural 7-day expiration, a significantly longer exposure window.

// The targeted, per-device revocation that resolved the incident
await db.refreshTokens.delete({ userId, deviceId: stolenLaptopDeviceId });

Interview Prep

Pascual Vila

Pascual Vila

Full-Stack Software and AI Engineer

Full-Stack Software and AI Engineer with 6 years of experience building enterprise-grade web applications across React, Angular, Node.js, and Python. Recently completed a Master's in AI Development specializing in LLMs, RAG, and AI agent architectures, and currently builds enterprise systems that integrate AI and Digital Twins to optimize industrial and logistics processes.

LinkedIn ↗
Common Pitfalls & Errors

The Error //

Storing a refresh token in localStorage instead of an HttpOnly cookie

// Wrong: readable by any XSS payload localStorage.setItem("refreshToken", token); // Correct: inaccessible to JavaScript res.cookie("refreshToken", token, { httpOnly: true, secure: true, sameSite: "strict" });

The Solution //

localStorage is fully readable by any JavaScript running on the page, including an injected XSS payload — storing a long-lived, high-value refresh token there means a successful XSS attack can steal it and maintain persistent unauthorized access far beyond a short-lived access token's exposure window. An HttpOnly cookie is inaccessible to JavaScript entirely.

The Error //

Issuing refresh tokens as purely stateless JWTs with no server-side record, making revocation impossible

// Wrong: no way to revoke this token before it naturally expires const refreshToken = jwt.sign({ userId }, SECRET, { expiresIn: "7d" }); // Correct: persisted, revocable await db.refreshTokens.insert({ token: hashedToken, userId, deviceId }); // Revocation: await db.refreshTokens.delete({ userId, deviceId });

The Solution //

A purely stateless refresh token remains valid until its natural expiration, with no way to invalidate it early — if a device is lost or an account is suspected compromised, there's no mechanism to revoke that specific refresh token's access before it naturally expires, which could be days or weeks later.

Continue Learning