DEV Community

Cover image for Understanding OAuth 2.0 Refresh Tokens
Ben Dechrai
Ben Dechrai

Posted on • Originally published at bendechr.ai on

Understanding OAuth 2.0 Refresh Tokens

If you've implemented authentication using OAuth 2.0 or OpenID Connect (OIDC), you've probably heard of refresh tokens. Maybe you've even configured an identity provider to issue them. But what exactly is the OAuth 2.0 Refresh Token Grant, and why does it exist?

Let me take you on a journey through one of OAuth's most misunderstood features, using a theme park analogy that'll make everything click.

The Problem: Security vs. User Experience

First, let's understand the key components in an OAuth 2.0 system:

Flowchart of a typical OAuth architecture.

Imagine you're building an app that needs to access protected resources on behalf of your users. You've implemented OAuth 2.0, and your users authenticate successfully. Great! Your app receives an access token that it can use to make API calls.

But here's the catch: access tokens expire. This is a good thing for security; if an access token gets leaked, the window of opportunity for an attacker is limited. If you're an online streaming service, maybe you're happy with a 24 hour expiry. If you're a bank, maybe it's minutes.

But what happens when that access token expires? Do you kick your user out and make them log in again? Every time?

That's a terrible user experience.

This is the problem refresh tokens solve.

The Theme Park Analogy

Instead of retrieving content based on protected data, let's have a fun day out by getting on theme park rides. You're staying at the resort for a week and have bought a multi-day pass with the unlimited food and beverage add-on.

When you arrive at the main entrance (the authorisation server), you join the queue and show your ID and credentials when you get to the front. After verifying who you are, the staff gives you two things:

  • A wristband - you'll scan this at every ride, locker, and food vendor throughout the day
  • A key card - you keep this safe in your wallet

Here's how it works throughout the day:

  • You want to ride the roller-coaster? Scan your wristband.
  • You want to rent a locker? Scan your wristband.
  • You want to buy food? Scan your wristband.

The wristband gets you access to everything, and you're using it constantly. This is your access token.

But here's the thing: your wristband expires at the end of the day. This security feature means that, if someone steals your wristband, they can only use it for a limited time.

The next morning, you rock up and want to get a new wristband for the day, but don't want to stand in the queue and go through the identification process again. This is not an ideal user experience for multi-day visitors.

Instead, you go to the self-service desk, scan your key card, and out pops a fresh wristband. No fuss, no crowds, no re-authentication. This is exactly what refresh tokens do.

How Refresh Tokens Work

Let's map the analogy to the actual OAuth 2.0 flow.

Initial Authentication

First, you arrive at the park and authenticate:

Flowchart describing the analogous theme park process of getting a wristband and key card.

Using Access Tokens and Refreshing

Throughout your visit, here's how the tokens work:

Flowchart describing the process of using a wristband to access theme park facilities and how its expiry would affect the user experience.

The key insight: Your key card (refresh token) is never shown at the rides, to access lockers, or to food vendors (resource servers). It's only ever presented to the self-service desk (authorisation server). This dramatically reduces its exposure.

Access Token vs. Refresh Token

Let's break down the difference:

Wristband (Access Token) Key Card (Refresh Token)
Used at Every ride, vendor, service Only at the self-service desk
Frequency Constantly (every API request) Rarely (only when access token expires)
Lifetime Minutes to hours Days to months
Exposure High (sent frequently) Low (rarely sent)
If stolen Limited damage window More valuable, requires more protection

The credential you use constantly (access token) has limited power and a short life.

The credential you use rarely (refresh token) is more powerful but far less exposed.

Security by Design

Refresh tokens are designed to be stored securely:

  • Server-side storage for web applications (never in browser localStorage)
  • Secure device storage for mobile apps (iOS Keychain, Android KeyStore)
  • HttpOnly cookies for browser-based flows
  • Never exposed in URLs or logs
  • Only ever sent to the authorisation server that issued it

This is like keeping your key card in a secure wallet or safe. You don't wave it around the park; you only pull it out at the designated self-service desk.

Because of this design, refresh token theft is relatively rare.

But Theft Can Still Happen

Despite these precautions, refresh tokens can be compromised:

  • Cross-Site Scripting (XSS) attacks can steal tokens from browser storage
  • Malicious browser extensions can intercept tokens
  • Compromised dependencies in your application code
  • Server-side breaches exposing stored tokens
  • Man-in-the-middle attacks if TLS isn't properly implemented

And when someone steals a refresh token, they don't really "steal" it, they make a copy of it.

In the physical world, if someone steals your key card, you no longer have it. But in the digital world, both you and the attacker have a working copy of the same refresh token. You can both use it to get new wristbands.

Sequence diagram showing how an attacker could use an acquired refresh token to obtain a valid access token.

So how do we detect that something's wrong?

Detection: Refresh Token Rotation

This is where refresh token rotation comes in. Here's how it works:

Every time you use your key card to get a new wristband, the park also gives you a brand new key card and invalidates the old one. Or maybe they just write a new token to your key card, but hey, it's an analogy...

Let's see what happens when a refresh token is compromised:

Sequence diagram showing how refresh token rotation can mitigate the risk of a refresh token being leaked.

The attacker is now locked out, and you're asked to verify your identity again. It's a bit inconvenient for you, but it's the security equivalent of finding out someone photocopied your credit card; you want everything shut down immediately.

Why This Matters for Developers

When implementing OAuth 2.0 in your applications, understanding refresh tokens helps you make better security and UX decisions:

You should use refresh tokens when:

  • Your app needs long-lived access to resources
  • You want to avoid repeatedly interrupting users with login screens
  • You're building mobile apps or SPAs with persistent sessions
  • You need to balance security with user convenience

You should implement rotation when:

  • You're handling sensitive data
  • You want to detect token theft
  • Your security requirements are high
  • You're following OAuth 2.0 BCP (Best Current Practice)

You should NOT use refresh tokens when:

  • You're building a short-lived, single-use flow
  • Your client can't securely store the refresh token (e.g., pure client-side JavaScript apps without a backend)
  • Your authorisation server doesn't support secure token management

Advanced Considerations

This introduction covers the fundamentals, but there are some real-world complications worth being aware of that are beyond the scope of this article. If you'd like me to cover any of these in another post, let me know in the comments!

Multiple browser tabs and token rotation : If users have your app open in multiple tabs, token rotation can create race conditions where one tab invalidates the refresh token that another tab is about to use, resulting in both tabs being locked out even though the user did nothing wrong. There are strategies to handle this (grace periods, shared storage, backend session patterns), but it requires careful architecture.

Secure token storage in SPAs : Pure frontend single-page applications face unique challenges in storing refresh tokens securely. Patterns like using Web Workers for token isolation and transparent reauthentication or implementing a Backend-for-Frontend (BFF) can help, but each comes with tradeoffs.

Token revocation and session management : Understanding when and how to manually invalidate tokens, whether due to user logout, password changes, or security events, is crucial for production systems. The relationship between OAuth tokens and application sessions can get complex.

Key Takeaways

Think of refresh tokens like a multi-day key card at a theme park:

  1. Access tokens (wristbands) are used constantly but expire quickly
  2. Refresh tokens (key cards) are rarely used but last much longer
  3. Refresh tokens are never sent to resource servers, only to the authorisation server
  4. Token rotation issues a new refresh token with each use, enabling theft detection. While this is a security best practice, it requires thoughtful implementation to handle edge cases like multiple browser tabs.

Refresh tokens solve a fundamental tension in OAuth 2.0: they keep users logged in without constantly exposing their credentials, while maintaining strong security through short-lived access tokens.

Final Words

Unless it is your job to do so, you should seriously reconsider before implementing your own authentication or authorisation systems. The same goes for implementing cryptographic algorithms, payment processing systems, etc.

This article is designed to help you understand the OAuth 2.0 Refresh Token Grant, and how it plays a part in the authorisation process, so that you can implement existing and proven systems more securely and with more confidence.


Have a burning question or comment? Hit me up below, or find me on LinkedIn or Bluesky. I'd love to hear from you.

Top comments (0)