If you build Frontend applications with React, Vue, or Angular, you’ve probably faced this scenario:
Your user's Access Token expires.
The user loads a dashboard that fires 3 API requests simultaneously.
All 3 requests fail with 401 Unauthorized.
Your app tries to refresh the token... 3 times in a row. 💥
The first refresh succeeds, but the second one invalidates the first one. The user gets logged out randomly.
This is called the Race Condition.
To fix this, you need a complex logic: A Promise Queue. You need to pause all failed requests, wait for one refresh to happen, and then retry them all with the new token.
I got tired of copy-pasting this boilerplate code into every project, so I built a tiny, battle-tested library to handle it for me.
Meet axios-auth-refresh-queue.
Why use this instead of coding it yourself?
⚡ Ultra-lightweight: It’s 641 Bytes (minified + gzipped). Yes, less than 1KB.
🛡 Bulletproof: Handles race conditions, infinite loops, and failed refreshes gracefully.
🐞 Debug Mode: Comes with a built-in logger to see exactly what's happening (Refreshing? Queuing? Retrying?).
🟦 TypeScript: Fully typed out of the box.
How to use it
It takes less than 2 minutes to set up.
Install
npm install axios-auth-refresh-queueThe Setup
You just need two things: a function to refresh your token and the interceptor setup.
import axios from 'axios';
import { applyAuthTokenInterceptor } from 'axios-auth-refresh-queue';
// 1. Create your Axios instance
const apiClient = axios.create({
baseURL: 'https://api.example.com',
});
// 2. Define your Refresh Logic
// This function should return the new access token
const requestRefresh = async (refreshToken: string) => {
const response = await axios.post('/auth/refresh', { token: refreshToken });
return {
accessToken: response.data.accessToken,
refreshToken: response.data.refreshToken,
};
};
// 3. Apply the interceptor
applyAuthTokenInterceptor(apiClient, {
requestRefresh, // The async function to call backend
debug: true, // 🐞 Enable console logs to see the magic!
onSuccess: (newTokens) => {
// Save new tokens to localStorage/Store
localStorage.setItem('token', newTokens.accessToken);
},
onFailure: (error) => {
// Refresh failed? Log the user out
console.error('Session expired', error);
window.location.href = '/login';
}
});
export default apiClient;
That's it! Now, whenever a 401 happens:
The library pauses all other requests.
It calls your requestRefresh function once.
It updates the header and retries all original requests automatically.
Cool Features
🐞 Debug Mode
Not sure if it's working? Just enable debug: true and check your console:
[Auth-Queue] 🚨 401 Detected from /api/user
[Auth-Queue] ⏳ Refresh already in progress. Adding to queue...
[Auth-Queue] ✅ Refresh Successful! Retrying queued requests.
⏩ Skip Auth
Need to call a public API that might return 401 but shouldn't trigger a refresh?
axios.get('/api/public-status', {
skipAuthRefresh: true
});
Give it a try!
I built this to save time for myself and my team, and I hope it helps you too. It’s open-source, fully tested, and ready for production.
📦 NPM: npmjs.com/package/axios-auth-refresh-queue
🐙 GitHub: https://github.com/Eden1711/axios-auth-refresh
If you find it useful, a ⭐️ on GitHub would mean the world to me!
Happy coding! 💻
Top comments (0)