Interceptors - how to prevent intercepted messages from resolving as error
Problem
I'm trying to make an interceptor for 401 responses that result from expired token. Upon interception I want to login and retry the requests with the new token. My problem is that login is also done asynchronously, so by the time the retry happens, the original promises reject. Is there a way around that? Here's my code: [code block]
Error Output
error => { console.log('Refresh login error: ', error) }Unverified for your environment
Select your OS to check compatibility.
1 Fix
Implement Token Refresh Logic in Axios Interceptor
The original promises reject because the asynchronous login process for obtaining a new token does not complete before the retry attempts are made. This leads to the original request failing with a 401 error, as the interceptor does not wait for the token refresh to complete before retrying the request.
Awaiting Verification
Be the first to verify this fix
- 1
Create a Token Refresh Function
Define a function that handles the token refresh logic. This function should return a promise that resolves with the new token once the login is successful.
javascriptasync function refreshToken() { const response = await axios.post('/auth/refresh'); return response.data.token; } - 2
Modify the Interceptor to Handle 401 Errors
Update the Axios interceptor to catch 401 errors and call the refreshToken function. Use a queue to manage requests that need to be retried after the token is refreshed.
javascriptaxios.interceptors.response.use( response => response, async error => { const originalRequest = error.config; if (error.response.status === 401 && !originalRequest._retry) { originalRequest._retry = true; const newToken = await refreshToken(); axios.defaults.headers.common['Authorization'] = 'Bearer ' + newToken; return axios(originalRequest); } return Promise.reject(error); } ); - 3
Handle Concurrent Requests
Implement a mechanism to handle multiple concurrent requests that may trigger the token refresh. Use a flag to prevent multiple refresh calls and queue subsequent requests until the token is refreshed.
javascriptlet isRefreshing = false; let subscribers = []; function onRefreshed(token) { subscribers.forEach(callback => callback(token)); subscribers = []; } function addSubscriber(callback) { subscribers.push(callback); } axios.interceptors.response.use( response => response, async error => { const originalRequest = error.config; if (error.response.status === 401 && !originalRequest._retry) { if (isRefreshing) { return new Promise((resolve) => { addSubscriber(token => { originalRequest.headers['Authorization'] = 'Bearer ' + token; resolve(axios(originalRequest)); }); }); } originalRequest._retry = true; isRefreshing = true; const newToken = await refreshToken(); axios.defaults.headers.common['Authorization'] = 'Bearer ' + newToken; onRefreshed(newToken); isRefreshing = false; return axios(originalRequest); } return Promise.reject(error); } ); - 4
Test the Implementation
After implementing the changes, test the interceptor by simulating a 401 error and ensuring that the token refresh logic works correctly and the original request is retried successfully.
javascript// Simulate a request that will fail with 401 axios.get('/protected/resource').catch(error => { console.log('Request failed:', error); });
Validation
Confirm that when a 401 error occurs, the interceptor successfully refreshes the token and retries the original request without rejecting the promise. Check the console logs for successful request completion.
Sign in to verify this fix
Environment
Submitted by
Alex Chen
2450 rep