Effortless Token Refresh in React Using Axios Interceptors

Keeping users logged in securely is essential for any modern web app. One way to achieve this is with token rotation-a method that automatically refreshes expired access tokens using a refresh token, all without interrupting the user experience. In this beginner-friendly guide, you'll learn how to implement token rotation in a React app using Axios interceptors, without interfering with your server logic. We'll also compare common token storage options so you can choose what's best for your project.
#What is Token Rotation?
Token rotation is a technique where, instead of keeping a refresh token forever, you get a new refresh token each time you use it. This makes your app more secure because even if a refresh token is stolen, it can only be used once before it becomes invalid.
#How Does Axios Interceptor Help?
Axios interceptors let you run logic before a request is sent or after a response is received. Here, we'll use a response interceptor to detect when an access token has expired and automatically fetch a new one using the refresh token-without the user noticing.
#Step-by-Step Example: Token Rotation with Axios
Below is a simple implementation.
// api.js
import axios from 'axios';
// Create an Axios instance
const api = axios.create({
baseURL: 'https://your-api-url.com', // Replace with your backend URL
});
// Function to get tokens from storage
const getTokens = () => {
return {
accessToken: localStorage.getItem('accessToken'),
refreshToken: localStorage.getItem('refreshToken'),
};
};
// Function to save tokens to storage
const setTokens = ({ accessToken, refreshToken }) => {
localStorage.setItem('accessToken', accessToken);
if (refreshToken) localStorage.setItem('refreshToken', refreshToken);
};
// Add the access token to every request
api.interceptors.request.use(config => {
const { accessToken } = getTokens();
if (accessToken) {
config.headers.Authorization = `Bearer ${accessToken}`;
}
return config;
});
// Handle token expiration and rotation
api.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config;
// If access token expired, try to refresh
if (
error.response &&
error.response.status === 401 &&
!originalRequest._retry
) {
originalRequest._retry = true;
const { refreshToken } = getTokens();
if (refreshToken) {
try {
// Request new access token
const res = await axios.post(
'/auth/refresh',
{
refreshToken,
}
);
// Save new tokens
setTokens(res.data);
// Retry the original request with new token
originalRequest.headers.Authorization = `Bearer ${res.data.accessToken}`;
return api(originalRequest);
} catch (refreshError) {
// Refresh token invalid, force logout or redirect to login
localStorage.clear();
window.location.href = '/login';
}
}
}
// Any other error
return Promise.reject(error);
}
);
export default api;
How it works:
Visual Flow
User clicks "Profile" →
Access token expired →
401 error →
Interceptor calls refresh endpoint →
Success? →
Retry original request →
User sees profile (no error)
Failure? →
Show login prompt (user sees error)
- Every request includes the access token.
- If the server returns 401 (Unauthorized), the interceptor tries to refresh the token using the refresh token.
- If successful, it retries the original request with the new access token.
- If refresh fails, it logs the user out.
#Token Storage Options: Pros & Cons
#1. Local Storage
#2. Session Storage
#3. HttpOnly Cookies
#Conclusion
With Axios interceptors, you can easily implement token rotation in your React app. This keeps users logged in seamlessly and securely, without extra hassle. Remember to choose the token storage method that best fits your security needs and app requirements.
Thank you for reading, and have a beautiful day! ❤️