Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Axios global interceptor for token refresh

OK, so this is my third wall I'm hitting with this problem, first off here's my axios config file

import axios from "axios";
import { withRouter } from "react-router-dom";

const instance = axios.create({
  baseURL: process.env.REACT_APP_API,
  headers: {
    "content-type": "application/json"
  },
  responseType: "json"
});
function pushToLogin() {
  this.props.history.push("/");
}
function createAxiosResponseInterceptor(axiosInstance) {
  const interceptor = axiosInstance.interceptors.response.use(
    response => response,
    error => {
      // Reject promise if usual error
      console.log(error);
      if (error.response.status !== 401) {
        return Promise.reject(error);
      }
      /*
       * When response code is 401, try to refresh the token.
       * Eject the interceptor so it doesn't loop in case
       * token refresh causes the 401 response
       */
      axiosInstance.interceptors.response.eject(interceptor);
      return axiosInstance
        .post("token/refresh/", {
          refresh: localStorage.getItem("refreshToken")
        })
        .then(response => {
          localStorage.setItem("accessToken", response.data.access);
          error.response.config.headers["Authorization"] =
            "Bearer " + response.data.access;
          return axiosInstance(error.response.config);
        })
        .catch(error => {
          localStorage.setItem("accessToken", null);
          localStorage.setItem("refreshToken", null);
          pushToLogin();
          return Promise.reject(error);
        })
        .finally(createAxiosResponseInterceptor(this));
    }
  );
}

createAxiosResponseInterceptor(instance);

export default withRouter(instance);

What I want, is: Request gets 401 > Get a new token and store it > repeat request > if it's good to go we're good, if not return it's normal error.

What's happening: Request gets 401 > Gets new token and stores it > Repeat request> if it's good we're good to go, if not, it goes into that final catch block on my interceptor, which I thought was intended specifically for the refreshToken request, or atleast that's what I desire it to be.

Bonus question: I'd like to push to login on refreshToken failure as u can see, I'm trying to use withRouter for that but I cannot read props of undefined on that push line, so that's another issue.

Many thanks!

Edit:Even if this request has been done by other ways I'd like to know what's wrong with my code than learn someone else's.

like image 327
Omar Hussein Avatar asked Nov 07 '19 15:11

Omar Hussein


Video Answer


1 Answers

I switched to using the axios-auth-refresh package, the config code I'm using is here:

import axios from "axios";
import createAuthRefreshInterceptor from "axios-auth-refresh";

const instance = axios.create({
  baseURL: process.env.REACT_APP_API,
  headers: {
    "content-type": "application/json"
  },
  responseType: "json"
});
const refreshAuthLogic = failedRequest =>
  instance
    .post("token/refresh/", {
      refresh: localStorage.getItem("refreshToken")
    })
    .then(tokenRefreshResponse => {
      localStorage.setItem("accessToken", tokenRefreshResponse.data.access);
      failedRequest.response.config.headers["Authorization"] =
        "Bearer " + tokenRefreshResponse.data.access;
      return Promise.resolve();
    })
    .catch(error => {
      console.log("refresh fail");
      localStorage.setItem("accessToken", null);
      localStorage.setItem("refreshToken", null);
      //pushToLogin();
      return Promise.reject(error);
    });
createAuthRefreshInterceptor(instance, refreshAuthLogic);

export default instance;
like image 55
Omar Hussein Avatar answered Sep 28 '22 11:09

Omar Hussein