Reputation: 43
I have looked the other questions about this problem but I could not fix it. I have a get request restriction for the refresh and access token renewal methods and there will be multiple requests in a page. Furthermore I have a different access-token/refresh token usage in our system.
UPDATE: Infinite loop issue is handled by creating an axios instance in the main instance. Now, I encounter a request cancellation problem often and couldn't solve it. After a request, access-token request is made but it is cancelled. I don't know why.
Below you can see the sequence diagrams:
So far, sometimes it works cursory, a request -> 401 access token expired error -> renew access token in interceptor and write it to localStorage -> same request resolves 200
But most of the time this happens and it continues with 401 loop for access-token:
Note: At the beginning of the access-token loop I get 401 including the "Staff not found" error description which means that in our system the renewed token is not included in the incoming non-token request(expired token is included in header). Normally the error description of the 401 error for non-token requests is "Token expired".
Possible noob question: How is it possible to have only one preflight and two xhr for a request?
Here is my service.js code:
const sendRequest = async (options) => {
let requestOptions = {
... // includes the method, data etc.
if (options.hasOwnProperty("token")) {
requestOptions.headers =
Object.assign(requestOptions.headers, {
Authorization: RequestOptionConstants.AUTHORIZATION +
options.token,
});
}
return await axios(
options.url, // includes the api url
requestOptions,
axios.interceptors.response.use(
(response) => {
return response;
},
async (error) => {
const originalConfig = error.config;
if (error.response.status === 401 && !originalConfig._retry) {
originalConfig._retry = true;
let refreshToken = JSON.parse(localStorage.getItem("user"))
.refreshToken;
// Check for refresh token expiration
if (jwtDecode(refreshToken).exp < new Date().getTime()) {
logout();
}.
await axios
.get(ApiConstants.GET_ACCESS_TOKEN, {
headers: {
Authorization:
"Bearer " +
JSON.parse(localStorage.getItem("user")).refreshToken,
},
})
.then((res) => {
if (res.status === 200) {
const user = JSON.parse(localStorage.getItem("user"));
originalConfig.headers["Authorization"] =
"Bearer " + res.data.accessToken;
user.accessToken = res.data.accessToken;
localStorage.setItem("user", JSON.stringify(user));
if (res.data.isRefreshTokenInRenewalPeriod) {
getRefreshToken(originalConfig);
}
return axios(originalConfig);
}
});
}
return Promise.reject(error);
}
))
.then(handleResponse, (error) => Promise.reject(error))
.then((data) => {
return data;
});
};
const handleResponse = (response) => {
const data = response.data;
if (!data?.result?.success ?? false) {
const error = data.result;
return Promise.reject(error);
}
return data;
};
function logout() {
localStorage.removeItem("user");
window.location.reload();
}
const getRefreshToken = () => {
axios
.get(ApiConstants.GET_REFRESH_TOKEN, {
headers: {
Authorization:
"Bearer " + JSON.parse(localStorage.getItem("user")).refreshToken,
},
})
.then((res) => {
if (res.status === 200) {
const user = JSON.parse(localStorage.getItem("user"));
user.refreshToken = res.data.refreshToken;
localStorage.setItem("user", JSON.stringify(user));
return axios();
}
})
.catch((error) => {
console.log(error);
});
};
Actually I tried "return new Promise" approach from Queue approach .
The Queue approach solved the infinite loop problem but I still encounter a 401 error with description 'staff not found' while renewing the refresh token this time. How can I solve the infinite loop problem of the async await approach?
SOLVED: I solved this problem with defining two other axios instances for accessToken and refreshToken and calling them in a sequence. Images are deleted because of the confidentiality.
Upvotes: 3
Views: 2973
Reputation: 21
Have you tried with axios.interceptors.response.eject() yet? It will help disable the interceptor when API called and re-enable it after. Example:
if (error.response.status === 401 && !originalConfig._retry) {
originalConfig._retry = true;
**// Add axios interceptors eject to avoid loop
axios.interceptors.response.eject();**
let refreshToken = JSON.parse(localStorage.getItem("user"))
.refreshToken;
// Check for refresh token expiration
if (jwtDecode(refreshToken).exp < new Date().getTime()) {
logout();
}
....
Upvotes: 2