DEV Community

Cover image for How Enterprise React Apps Handle JWT Token Refresh Automatically
codeek
codeek

Posted on

How Enterprise React Apps Handle JWT Token Refresh Automatically

Access Token & Refresh Token Authentication in React (Axios + React Query)

Authentication is one of the most critical parts of modern web applications. In enterprise applications, simply storing a JWT and sending it with every request isn't enough. We need a secure mechanism that provides a seamless user experience while protecting user sessions.

This is where Access Tokens and Refresh Tokens come into play.

In this article, we'll understand how a production-ready authentication flow works using React, Axios, and React Query.

Why Do We Need Two Tokens?

A common question developers ask is:

"Why not just use one JWT token?"

The answer is security.

Imagine your access token is stolen. If it never expires, an attacker could access your APIs indefinitely.

Instead, enterprise applications separate authentication into two different tokens:

Access Token
Refresh Token
Access Token

An Access Token is a short-lived JWT that is sent with every protected API request.

Characteristics
✅ Sent with every API request
✅ Usually expires within 5–15 minutes
✅ Stored only in memory (recommended) or a secure cookie
✅ Contains user identity and permissions
Example
Authorization: Bearer eyJhbGciOi...
Refresh Token

A Refresh Token has a completely different responsibility.

Instead of accessing APIs, it is used only to obtain a new Access Token after the current one expires.

Characteristics
✅ Long-lived (days or weeks)
✅ Never sent with every request
✅ Stored inside an HttpOnly Secure Cookie
✅ Sent only to the refresh endpoint
Initial Login Flow
User Login


Backend validates credentials


Returns
├── Access Token (15 min)
└── Refresh Token (7 days)
Authentication Flow

A typical enterprise authentication flow looks like this:

User Login


Backend validates credentials


Returns:
• Access Token
• Refresh Token


Frontend stores Access Token
Refresh Token stays inside HttpOnly Cookie


User makes API requests


Access Token expires


Axios detects 401 Unauthorized


Calls /auth/refresh


Backend validates Refresh Token


Returns new Access Token


Retry original request

The user never has to log in again while the Refresh Token remains valid.

Why Store Refresh Token in an HttpOnly Cookie?

Many beginners store both tokens in localStorage.

This is not recommended.

If your application suffers from an XSS (Cross-Site Scripting) attack, JavaScript can read everything stored in localStorage.

An HttpOnly Cookie cannot be accessed by JavaScript, making it significantly more secure.

Recommended Storage Strategy
Token Storage
Access Token Memory (React State, Zustand, Redux, etc.)
Refresh Token HttpOnly Secure Cookie
Using Axios Interceptors

Axios Interceptors allow us to intercept every request and response globally.

Instead of checking token expiration inside every API call, we centralize the authentication logic.

Request Interceptor

Before every request:

Read the current Access Token
Attach it to the Authorization header
Authorization: Bearer accessToken

No need to manually attach tokens every time.

Response Interceptor

When the backend returns 401 Unauthorized:

Pause the failed request.
Call the refresh endpoint.
Receive a new Access Token.
Update the stored token.
Retry the original request.

The user never notices that the Access Token expired.

Where Does React Query Fit?

React Query is responsible for:

Server state
Data fetching
Caching
Background refetching
Automatic retries

Authentication should not be mixed into every query.

Instead, the architecture should look like this:

React Query


Axios Instance


Axios Interceptors


Backend APIs

React Query simply calls Axios.

Axios automatically handles authentication.

This separation keeps your application clean, reusable, and maintainable.

Example Flow with React Query

Suppose we're fetching a user's profile.

useQuery()


Axios GET /profile


401 Unauthorized


Axios refreshes token


Retries request


Profile returned


React Query updates cache

Notice that React Query never needs to know about authentication.

Everything happens transparently.

Prevent Multiple Refresh Requests

Imagine five API requests are sent simultaneously.

If the Access Token expires, every request receives:

401 Unauthorized

Without proper handling:

Refresh
Refresh
Refresh
Refresh
Refresh

This creates:

Duplicate refresh requests
Race conditions
Unnecessary server load
Better Approach
First request

Starts refresh

───────────────
Other failed requests wait
───────────────

New Access Token received

Retry all queued requests

This queueing strategy is commonly used in enterprise applications.

Logout Flow

Eventually, the Refresh Token also expires.

When refreshing fails:

401 Unauthorized


Refresh Failed


Clear user state


Redirect to Login

This ensures invalid sessions are cleaned up properly.

Best Practices
✅ Keep Access Tokens short-lived (5–15 minutes)
✅ Store Refresh Tokens inside HttpOnly Secure Cookies
✅ Store Access Tokens in memory whenever possible
✅ Use Axios Interceptors for automatic token refresh
✅ Keep authentication logic outside React Query
✅ Retry the original request after refreshing the token
✅ Queue failed requests during refresh to prevent duplicate refresh calls
✅ Clear authentication state when refresh fails
Architecture Overview
React Components


React Query


Axios Instance


Request Interceptor


Protected API

401 Unauthorized


Response Interceptor


Refresh Endpoint


New Access Token


Retry Original Request
Conclusion

Using Access Tokens and Refresh Tokens is the industry standard for building secure authentication systems.

By combining Axios Interceptors with React Query, you can create a seamless authentication experience where expired tokens are refreshed automatically without interrupting the user.

Keeping authentication inside the Axios layer also makes your React Query hooks simple, reusable, and focused only on fetching data.

🎥 Video Tutorial

If you prefer learning through video, check out the complete guide:

How to Automatically Refresh JWT Tokens in React

https://www.youtube.com/watch?v=ntr2CCoeP8o&t=71s

If you found this article helpful, consider leaving a ❤️, sharing it with other developers, and following me for more React, TypeScript, and full-stack development content.

Top comments (0)