I would like to stop the infinite loop that I am getting with my axios interceptors.
When the user logs in, tokens are set in the local storage.
To test if token are being handled well, I change the value of the refresh token, and delete the access token, from the local storage.
When i do that, the user is suposed to be redirected to the login page, but it ends up in a infinite loop, unauthorized 401 error.
import axios from "axios";
import { logout } from "../stores/actions/authActions";
import store from "../stores";
import userEnv from "userEnv";
import { REFRESH_TOKEN_ENDPOINT } from "../constants/apiUrlConst";
import { ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY } from "../constants/tokenConst";
const axiosInstance = axios.create({
baseURL: userEnv.apiUrl,
});
const refreshAccessToken = async () => {
const refresh_token = localStorage.getItem(REFRESH_TOKEN_KEY);
if (!refresh_token) {
store.dispatch(logout());
localStorage.clear();
window.location.href = "/";
} else {
try {
const response = await axiosInstance.get(REFRESH_TOKEN_ENDPOINT);
const access_token = response.data.access_token;
const new_refresh_token = response.data.refresh_token;
localStorage.setItem(ACCESS_TOKEN_KEY, access_token);
localStorage.setItem(REFRESH_TOKEN_KEY, new_refresh_token);
return access_token;
} catch (error) {
return Promise.reject(error);
}
}
};
axiosInstance.interceptors.request.use(
async (config) => {
const url = config.url.toLowerCase();
const method = config.method.toLowerCase();
const token =
url === REFRESH_TOKEN_ENDPOINT && method === "get"
? localStorage.getItem(REFRESH_TOKEN_KEY)
: localStorage.getItem(ACCESS_TOKEN_KEY);
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
axiosInstance.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
// 401 Unauthorized
const originalRequest = error.config;
if (error.response?.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
try {
await refreshAccessToken();
return axiosInstance(originalRequest);
} catch (error) {
return Promise.reject(error);
}
}
return Promise.reject(error);
}
);
export default axiosInstance;
Could anyone help me find whats causing this loop, and how do i stop it?
2
Answers
One possible solution is to add a boolean flag to track if the refresh token has already been refreshed. this will prevent the interceptor from repeatedly retrying the request if it fails.
by checking for this flag, the interceptor will only attempt to refresh the token once, preventing the infinite loop.
If the above method didn’t worked, you can try adding a check for the
error.response.data
in the interceptor. Since refresh tokens can expire or become invalid, the401
error may not always be caused by the need for a refreshed token. By checking the error response, it can determined if the401
error is due to an invalid or expired refresh token, and only then attempt to refresh it.preventing the interceptor from continuously attempting to refresh the token for other types of
401
errors, such as expired access tokens.