Axios - Refresh token loop

Viewed 1855

so im rather new to axios and context but I have an Auth context that is provided at App level and this context is used by multiple child components. Within this context I have an axios interceptor that checks requests for 401 (unauthorized) and then calls the refresh token api and replaces the token with a new one. My only concern is that the second time the refresh token API is called it goes into an endless loop of calling the refresh token api? Any ideas what im doing wrong? Any help would be greatly appreciated.

AuthContext.js

  axios.interceptors.response.use((response) => {
    return response
  }, function (error) {
    const originalRequest = error.config;

    if (error.response.status === 401 && originalRequest.url ===
      `${BASE_URI}/Identity/Login`) {
      history.push('/login');
      return Promise.reject(error);
    }

    if (error.response.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      const localStorage = JSON.parse(sessionStorage.getItem(AUTH_USER))
      const refreshToken = localStorage.refreshToken;
      return axios.post(`${BASE_URI}/Identity/Refresh`, null,
      {
        headers: {
          'Refresh-Token': refreshToken
        }
      })
      .then(res => {
        if (res.status === 201 || res.status === 200) {
          console.log("In refresh request !")
          console.log(res)
          setSession(null, res.data.token, res.data.refreshToken)
          axios.defaults.headers.common['authorization'] = 'Bearer ' + res.data.token;
          return axios(originalRequest);
        }
      }).catch((error) => {
          console.log("Inside error refresh")
          return Promise.reject(error);
      })
  }
  return Promise.reject(error);
});

3 Answers

I have done something similar to get a refresh token when the token expires and I have encountered the same problem, actually, you are using the same instance of Axios, create another instance

const instance = axios.create();

axios.interceptors.request.use(async (config) => {
    if (token && refreshToken) {
        const data = JSON.parse(atob(token.split('.')[1]));
        const time = Math.floor(new Date().getTime() / 1000);
        if (data.exp < time) {
             instance.defaults.headers.common["Authorization"] = `Bearer ${refreshToken}`;
             const { data } = await instance.get(SERVER.API_ROOT + '/tokens/refresh');
             if (data?.AccessToken) localStorage.setItem(config.AUTH_TOKEN, data.AccessToken)
                else localStorage.clear();
            }
     return config;
}

Hope the above example will help you

Hey I know this is an old question, but it seems that your problem was using the same axios instance to request a refresh token, essentially creating a nested refresh-token cycle. What you could do is create a new axios instance (alongside with the initial instance, you would use them both) without an interceptor like this: const noInterceptAxios = axios.create();, and then later use it to send requests where you don't need to check the access token, return noInterceptAxios.post(`/Identity/Refresh).then().catch().

Related