Oğulcan Karayel
Oğulcan Karayel

Reputation: 425

React axios interceptor for refresh token

I have an react app that uses an express api . I am trying to refresh token when access token is expired. I am using axios interceptor for this achievement .

let isRefreshing = false;
let failedQueue = [];

const processQueue = (error, accessToken = null) => {
  failedQueue.forEach((prom) => {
    if (error) {
      prom.reject(error);
    } else {
      prom.resolve(accessToken);
    }
  });

  failedQueue = [];
};

axiosInstance.interceptors.response.use(
  async (response) => {
    return response;
  },
  async (error) => {
   
    const { status, data } = error.response;
    const originalRequest = error.config;  
    if (error.response.status===401 && data.message === "Invalid refresh token") {
        console.log("unauthorized");
       store.dispatch(authActions.logout());
        return;
      }
      
      if(error.response.status === 401 && data.message === "You are not authorized to access this route,you don't have a valid refresh token to create new access token "){
        console.log("invalid refresh token");
        console.log(error.response)
        store.dispatch(authActions.logout());
        return error.response;
      }

      if (error.response.status === 401 && !originalRequest._retry) {
        if (isRefreshing) {
          console.log("isRefreshing");
          return new Promise((resolve, reject) => {
            console.log("isRefreshing2");
            failedQueue.push({ resolve, reject });
          })
            .then((accessToken) => {
              console.log("access")
              originalRequest.headers["Authorization"] =
                "Bearer:" + accessToken;
              console.log("access: " + accessToken);
              return axiosInstance(originalRequest);
            })
            .catch((err) => {
              console.log("err");
              return Promise.reject(err);
            });
        }
        console.log("no refreshing"); 
        originalRequest._retry = true;
        console.log(originalRequest._retry);
        isRefreshing = true;
        return new Promise((resolve, reject) => { 
          postMethod("auth/token",null,null).then((result) => {
            console.log("result:",result)

              setToken(result.data.access_token);
              
              axiosInstance.defaults.headers.common["Authorization"] =
                "Bearer:" + result.data.access_token;
              originalRequest.headers["Authorization"] =
                "Bearer:" + result.data.access_token;

              processQueue(null, result.data.access_token);
              resolve(axiosInstance(originalRequest));
            })
            .catch((err) => {

              console.log(err.response)
              processQueue(err, null);
              reject(err);
            })
            .then(() => {
              isRefreshing = false;
            });
          //TODO:Eğer refresh tokenın da süresi dolmuşsa burda history.push oluyor. ama diğer tarafı bozuyor
        });
      } 
      return Promise.reject(error);
  }
);

It stuck somewhere. I used console.log to debug it . From console;

POST http://localhost:5000/api/auth/token?null 401 (Unauthorized)

no refreshing // it is first line after from third if statement

POST http://localhost:5000/api/auth/token?null 401 (Unauthorized)

isRefreshing // it comes from third if statement

isRefreshing2 // it comes from third if statement

After that nothing happen. What should I do ? Thanks for any help

Upvotes: 1

Views: 20602

Answers (2)

jeany
jeany

Reputation: 107

Follow my code below

const axios = require('axios');
import store from '../redux/store';
import AsyncStorage from '@react-native-async-storage/async-storage';
// create your axis here
const axiosService = axios.create({
  headers: {
    'Content-Type': 'application/json',
    Accept: 'application/json',
    Authorization: `Bearer ${yourTokenHere}`,
  },
});

axiosService.interceptors.response.use(
  response => {
    return response;
  },
  async error => {
    // unauthen error 401
    let originalConfig = error.config;
    if (error.response.status === 401) {
      // get token from storage
      const token = await AsyncStorage.getItem('token');
      if (token) {
        // call function hanldeRefresh
        const respRefresh = await handleRefresh(token);
        if (respRefresh && respRefresh.status === 200) {
          const filterToken =
            respRefresh.headers.authorization.split('Bearer ')[1];
          // save new refresh token to storage
          AsyncStorage.setItem('token', filterToken);
          // reset header for originalConfig with new token here
          originalConfig = {
            ...originalConfig,
            headers: {
              ...originalConfig.headers,
              Authorization: `Bearer ${filterToken}`,
            },
          };
          // dispatch action save new token to state for redux saga
          store.dispatch({
            type: 'REFRESH_TOKEN_SAGA',
            payload: filterToken && filterToken,
          });
        }
      }
      // continue send currently request
      return axiosService(originalConfig);
    }
    return Promise.reject(error.response.data);
  },
);

// function handle refresh token

// create new axios to avoid loop error 401 for axios response if refresh token die

const axiosServiceRefresh = axios.create({
  headers: {
    'Content-Type': 'application/json',
    Accept: 'application/json',
  },
});
const handleRefresh = async token => {
  // set header for axios refresh
  axiosServiceRefresh.defaults.headers.common.Authorization = `Bearer ${token}`;
  return new Promise((resolve, reject) => {
    axiosServiceRefresh
      .post(yourRefreshTokenPath, param)
      .then(response => {
        resolve(response);
      })
      .catch(error => {});
  });
};

Hope can help!

Upvotes: 1

Domnic Amalan
Domnic Amalan

Reputation: 94

const axiosInstance = axios.create({
     baseURL: baseURL,
     timeout: 5000,
     headers: {
                'Authorization': localStorage.getItem('access_token') ? "JWT " + localStorage.getItem('access_token') : null,
                'Content-Type': 'application/json',
                'accept': 'application/json'
     }
});

axiosInstance.interceptors.response.use(
    response => response,
    error => {
        const originalRequest = error.config;

        // Prevent infinite loops
        if (error.response.status === 401 && originalRequest.url === baseURL+'token/refresh/') {
            window.location.href = '/login/';
            return Promise.reject(error);
        }

        if (error.response.data.code === "token_not_valid" &&
            error.response.status === 401 && 
            error.response.statusText === "Unauthorized") 
            {
                const refreshToken = localStorage.getItem('refresh_token');

                if (refreshToken){
                    const tokenParts = JSON.parse(atob(refreshToken.split('.')[1]));

                    // exp date in token is expressed in seconds, while now() returns milliseconds:
                    const now = Math.ceil(Date.now() / 1000);
                    console.log(tokenParts.exp);

                    if (tokenParts.exp > now) {
                        return axiosInstance
                        .post('/token/refresh/', {refresh: refreshToken})
                        .then((response) => {
            
                            localStorage.setItem('access_token', response.data.access);
                            localStorage.setItem('refresh_token', response.data.refresh);
            
                            axiosInstance.defaults.headers['Authorization'] = "JWT " + response.data.access;
                            originalRequest.headers['Authorization'] = "JWT " + response.data.access;
            
                            return axiosInstance(originalRequest);
                        })
                        .catch(err => {
                            console.log(err)
                        });
                    }else{
                        console.log("Refresh token is expired", tokenParts.exp, now);
                        window.location.href = '/login/';
                    }
                }else{
                    console.log("Refresh token not available.")
                    window.location.href = '/login/';
                }
        }
      
     
      // specific error handling done elsewhere
      return Promise.reject(error);
  }
);

Upvotes: 4

Related Questions