Seamless Authentication: Handling Token Expiry Without Re-Login
Published on 2026-02-16 16:30 by Frugle Me (Last updated: 2026-02-16 17:35)
Seamless Authentication: Handling Token Expiry Without Re-Login
Nothing kills user retention like a "Session Expired" popup. To keep users engaged, you need a strategy that refreshes credentials silently in the background. Here is the industry-standard approach using Refresh Tokens and Axios Interceptors.
1. The Strategy: Dual Token System
Instead of one long-lived token, use two:
* Access Token: Short-lived (15–60 mins). Used for every API request.
* Refresh Token: Long-lived (7–30 days). Used only to get a new Access Token.
2. The Workflow
- The client sends an expired Access Token.
- The server returns a 401 Unauthorized error.
- The client "catches" this error, sends the Refresh Token to a
/refreshendpoint. - The server validates the Refresh Token and sends back a new Access Token.
- The client retries the original failed request with the new token.
3. Implementation (JavaScript/Axios)
This code uses an Axios Interceptor to automate the process so your UI components never even know a refresh happened.
```javascript
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.yourdomain.com',
});
// Request interceptor to attach the current token
api.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = Bearer ${token};
}
return config;
});
// Response interceptor to handle 401 errors
api.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
// If error is 401 and we haven't retried yet
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
const refreshToken = localStorage.getItem('refresh_token');
// Call your refresh endpoint
const res = await axios.post('https://api.yourdomain.com', {
token: refreshToken
});
if (res.status === 200) {
const { accessToken } = res.data;
localStorage.setItem('access_token', accessToken);
// Update the header and retry the original request
originalRequest.headers.Authorization = `Bearer ${accessToken}`;
return api(originalRequest);
}
} catch (refreshError) {
// Refresh token is also expired/invalid -> Force Logout
localStorage.clear();
window.location.href = '/login';
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);
export default api;
Comments (0)
Want to join the conversation?
Please log in to add a comment.