I have a refresh token that needs to be refreshed every 2 minutes. In order to do this I check for a 401 response (using an axios interceptor). If the response from the server is "expired" I retry the api call with a new token I get from making a new POST request to a token endpoint.
const REFRESH_TOKEN_ERRORS = ["token_expired", "invalid_token"];
export const apiHeaders = {
Authorization: `Bearer ${window.localStorage.getItem("jwt")}`,
"Content-Type": "application/json",
};
axios.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
const originalRequest = error.config;
const apiUrl = String(process.env.REACT_APP_API_ROOT);
if (originalRequest.url.includes(apiUrl)) {
// REFRESH_TOKEN_ERRORS contains a list of specific error messages in the API body that should trigger refresh & retry
if (
REFRESH_TOKEN_ERRORS.includes(error.response.data.error_description) &&
!originalRequest._retry
) {
originalRequest._retry = true;
// refresh and set the new headers
const newToken = await getNewRefreshToken();
if (newToken === null) {
return null;
}
axios.defaults.headers.common["Authorization"] = "Bearer " + newToken;
if (originalRequest.config) {
originalRequest.config.headers = apiHeaders;
} else {
originalRequest.headers = apiHeaders;
}
// Retry the original request
return axios(originalRequest);
}
} else {
console.log("Unhandled error", error.response.data);
}
return Promise.reject(error);
}
);
async function getNewRefreshToken() {
// https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow#refresh-the-access-token
const tokenUrl = process.env.REACT_APP_OAUTH_ROOT_URL + "/oauth2/token";
const clientId = process.env.REACT_APP_OAUTH_CLIENT_ID;
const refreshToken = window.localStorage.getItem("jwt_refresh_token");
try {
const res = await axios.post(
tokenUrl,
{},
{
headers: {
grant_type: "refresh_token",
client_id: String(clientId),
refresh_token: String(refreshToken),
},
}
);
window.localStorage.setItem("jwt", res.data.access_token);
window.localStorage.setItem("jwt_exp", res.data.exp);
window.localStorage.setItem("jwt_refresh_token", res.data.refresh_token);
return res.data.access_token;
} catch (err) {
console.log("Refresh error", err);
window.localStorage.removeItem("jwt");
window.localStorage.removeItem("jwt_refresh_token");
window.localStorage.removeItem("jwt_exp");
return null;
}
}
This works fine until I try and poll the api at intervals (e.g,. every 5 seconds)
This triggers the axios interceptor and the function is run again (effectively resetting my refresh token every 5 seconds instead of every 2 minutes).
How can I ensure that the refresh token is not reset every 5 seconds/how can I implement polling and refreshing of tokens without the above conflicts?
With my current implementation (whilst polling) I get a "invalid_token" response from the server after 2 minutes and the interceptor does not perform a silent re-request of the refresh token as I would like