Reputation: 85
I am using an Axios interceptor (in React) to retry on 401 (when my access token expires). I want to limit to one retry but for some reason I'm unable to read the retried property I am defining.
This is the code I am using in the interceptor.
const responseIntercept = axios.interceptors.response.use(
(response) => response,
async (error) => {
const prevRequest = error?.config;
console.log(prevRequest);
console.log(prevRequest.retried);
if (error?.response?.status === 401 && !prevRequest?.retried) {
await new Promise(r => setTimeout(r, 1500)); // only here to delay the infinite retries
prevRequest.retried = true;
// log here returns true
const newAccessToken = await refresh();
prevRequest.headers['Authorization'] = newAccessToken;
return axios(prevRequest);
}
return Promise.reject(error);
}
);
For some reason, logging of prevRequest shows an object with the property retried, but the second log of .retried always logs 'undefined'. I assume this is the problem but I have no idea why I can see the property set but can't access it.
If I log prevRequest after adding the property, it does return true.
Edit (solution): After taking bogdanoff's advice, this is the working solution I ended up with:
const NO_RETRY_HEADER = 'x-no-retry'
...
const responseIntercept = axiosPrivate.interceptors.response.use(
(response) => response,
async (error) => {
var prevRequest = error?.config;
if (error?.response?.status === 401 && prevRequest?.headers[NO_RETRY_HEADER] == null) {
// get new token, return error if refresh errors
try {
const newAccessToken = await refresh(controller.signal);
// retry with new token
prevRequest.headers[NO_RETRY_HEADER] = 'true';
prevRequest.headers['Authorization'] = newAccessToken;
return axiosPrivate(prevRequest);
} catch (error) {/* no-op */}
}
return Promise.reject(error);
}
);
Upvotes: 5
Views: 3042
Reputation: 2358
I have been there recently, I used headers instead of modifying config.
const NO_RETRY_HEADER = 'x-no-retry'
const responseIntercept = axios.interceptors.response.use(undefined, async (error) => {
if (!axios.isCancel(error) && axios.isAxiosError(error) && error.response.status === 401) {
if (error.config.headers && error.config.headers[NO_RETRY_HEADER]) {
return Promise.reject(error)
}
error.config.headers ||= {}
error.config.headers[NO_RETRY_HEADER] = 'true' // string val only
const newAccessToken = await refresh()
error.config.headers['Authorization'] = newAccessToken
return axios(error.config)
}
return Promise.reject(error)
})
Upvotes: 3