Resending a request that was made with an expired token is leading to status pending in developer tools

Viewed 735

I have a react application where I am trying to implement JWT.

I am using the axios interceptor where I catch status 401 returned by the server due to expired token, send the refresh token to server, receive the new access token in the client and then resend the original failed request.

The problem I am facing is that, when I resend the original failed request, the status appears as pending forever in the developer tools, network tab. The original failed request is a POST request, when I checked the database it was updated. So why is it showing pending status in the developer tools ?

Here is my axios interceptor code

import axios from 'axios'
// import refreshToken from '../src/Store/refreshToken'
import { store } from '../src/index'
import { removeAuth } from '../src/Store/actions/authAction'

const api = axios.create({
    baseURL: process.env.REACT_APP_SERVER
}) 

function createAxiosResponseInterceptor(axiosInstance) {
    axiosInstance.interceptors.request.use(function (config) {
        const token = localStorage.getItem('token');
        if (token){
            config.headers.Authorization = token;
            }
        return config
        }
    )

    axiosInstance.interceptors.response.use(
        response => {
            return response;
        },
        error => {
            var errorStatus = error.response.status;
           
            
            if (errorStatus === 401){                                   // status 401 is used when token is expired
                let cookies = document.cookie
                let refresh = cookies.split("refresh=")[1].split(';')[0]
                if(!sendRefreshToken(refresh, error)) {
                    store.dispatch(removeAuth({isLoggedIn: false}));
                    localStorage.setItem('token', '');
                    document.cookie = "refresh=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
                }
            }
            return error
        }
    );
}

function sendRefreshToken(refreshToken, error) {
    let result = api.post('/refresh', {
                        refreshToken: refreshToken
                    })
                    .then(response => {
                        if (response.data.success && response.data.message === "new access token set") {
                            localStorage.setItem('token', response.data.newToken)
                            api({                                               // Here I am resending the failed request.
                                method: error.response.config.method,
                                url: error.response.config.url,
                                data: JSON.parse(error.response.config.data)
                            }).then(response => {
                                console.log(response)
                                return true
                            })
                            .catch(error => {
                                console.log(error)
                                return false
                            })
                        }
                    })
                    .catch(error => {
                        console.log(error)
                        return false
                    })
    return result
}



createAxiosResponseInterceptor(api);

export default api;  

Please let me know if you find anything wrong with the code. Let me know if this is the right way to do it. Open to offer more bounty points.

1 Answers

Consider this article for reference. https://medium.com/swlh/handling-access-and-refresh-tokens-using-axios-interceptors-3970b601a5da

import axios from 'axios'
// import refreshToken from '../src/Store/refreshToken'
import { store } from '../src/index'
import { removeAuth } from '../src/Store/actions/authAction'

const api = axios.create({
    baseURL: process.env.REACT_APP_SERVER
})

function createAxiosResponseInterceptor(axiosInstance) {
    axiosInstance.interceptors.request.use(function (config) {
        const token = localStorage.getItem('token');
        if (token){
            config.headers.Authorization = token;
            }
        return config
        }
    )

    axiosInstance.interceptors.response.use(
        response => {
            return response;
        },
        error => {
            var errorStatus = error.response.status;

            const originalRequest = error.config;
          
            if (
              error.response.status === 401 &&
              !originalRequest._retry
            ) {

              originalRequest._retry = true;
              return api
              .post('/refresh', {
                refreshToken: getRefreshToken()
            })

                .then((jsonRefreshResponse) => {
                  if (jsonRefreshResponse.status === 200) {


                    // 1) put token to LocalStorage
                    saveRefreshToken(
                      jsonRefreshResponse.data.refreshToken
                    );
                    // 2) Change Authorization header

                    const newAccessToken = getJwtToken();
                  
                    setAuthHeader(newAccessToken);


                    // 3) return originalRequest object with Axios.
                 //   error.response.config.headers[
                 //     "Authorization"
                 //   ] = `Bearer ${newAccessToken}`;
                    setAuthHeader(newAccessToken)
                    return axios(error.response.config);
                  }
                })
                .catch((err) => {
                  console.warn(err);
                })

              }

              if (error.config) {
                console.log(error.config);
                return Promise.reject();
              }
        }
    );
}

export const setAuthHeader = (token) => {
  api.defaults.headers.common["Authorization"] = `Bearer ${token}`;
};



createAxiosResponseInterceptor(api);

export default api;

//These methods could be in separate service class
const getJwtToken=()=> {
  return localStorage.getItem("token");
}
const getRefreshToken=() =>{
  return localStorage.getItem("refreshToken");
}
const saveJwtToken=(token)=> {
  localStorage.removeItem("token");
  localStorage.setItem("token", token);
}
const saveRefreshToken=(refreshToken)=> {
  localStorage.setItem("refreshToken", refreshToken);
}
Related