J.Naude
J.Naude

Reputation: 155

Axios - Refresh token loop

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);
});

Upvotes: 2

Views: 3073

Answers (3)

Tapan Dave
Tapan Dave

Reputation: 37

@J.Naude I have done he similar thing but a generic wrapper around axios which i wrote for one of my project that handles almost all the edge cases

https://gist.github.com/tapandave/01960228516dd852a49c74d16c0fddb1

Upvotes: 1

Nilesh Sahitya
Nilesh Sahitya

Reputation: 21

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

Upvotes: 2

Nazar Klymenko
Nazar Klymenko

Reputation: 63

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().

Upvotes: 1

Related Questions