Last active
August 18, 2022 11:03
-
-
Save anlisha-maharjan/4789b7e4304436e6c9f0fbeff41658d4 to your computer and use it in GitHub Desktop.
Axios token interceptor sends a refresh token request when token is invalid, to get new token after which all the requests that failed initially are then sent again, but this time with a new token gotten from the refresh token request.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import axios from "axios"; | |
// Create axios request | |
const request = axios.create({ | |
baseURL: '', // Base url | |
headers: { | |
Accept: "application/json", | |
"Content-Type": "application/json", | |
}, | |
}); | |
export default request; | |
// Add a request interceptor | |
request.interceptors.request.use( | |
async function (config) { | |
// Add authorization headers before request is sent | |
config.headers["Authorization"] = "Bearer " + localStorage.getItem("token"); | |
return config; | |
}, | |
function (error) { | |
// Do something with request error | |
return Promise.reject(error); | |
} | |
); | |
// Add a response interceptor | |
request.interceptors.response.use( | |
function (response) { | |
// Any status code that lie within the range of 2xx cause this function to trigger | |
// Do something with response data | |
return response; | |
}, | |
async function (error) { | |
// Any status codes that falls outside the range of 2xx cause this function to trigger | |
// Do something with response error | |
if (error.response && error.response.status === 401) { | |
return resetTokenAndReattemptRequest(error); | |
} | |
// If the error is due to other reasons, we just throw it back to axios | |
return Promise.reject(error); | |
} | |
); | |
let isAlreadyFetchingAccessToken = false; | |
// This is the list of waiting requests that will retry after the JWT refresh complete | |
let subscribers = []; | |
async function resetTokenAndReattemptRequest(error) { | |
try { | |
const { response: errorResponse } = error; | |
// Get expired token | |
const resetToken = localStorage.getItem("token"); | |
if (!resetToken) { | |
// We can't refresh, throw the error anyway | |
return Promise.reject(error); | |
} | |
/* Proceed to the token refresh procedure | |
We create a new Promise that will retry the request,clone all the request configuration from the failed request in the error object. */ | |
const retryOriginalRequest = new Promise((resolve) => { | |
/* We need to add the request retry to the queue since there another request that already attempt to refresh the token */ | |
addSubscriber((token) => { | |
errorResponse.config.headers.Authorization = "Bearer " + token; | |
resolve(axios(errorResponse.config)); | |
}); | |
}); | |
if (!isAlreadyFetchingAccessToken) { | |
isAlreadyFetchingAccessToken = true; | |
const response = await axios({ | |
method: "get", | |
url: '', // Refresh token api endpoint | |
headers: { | |
Accept: "application/json", | |
Authorization: "Bearer " + resetToken, | |
}, | |
}); | |
if (!response.data) { | |
return Promise.reject(error); | |
} | |
// Save new token in localStorage | |
localStorage.setItem("token", response.data.data.refreshToken); | |
isAlreadyFetchingAccessToken = false; | |
onAccessTokenFetched(response.data.data.refreshToken); | |
} | |
return retryOriginalRequest; | |
} catch (err) { | |
return Promise.reject(err); | |
} | |
} | |
function onAccessTokenFetched(token) { | |
// When the refresh is successful, we start retrying the requests one by one and empty the queue | |
subscribers.forEach((callback) => callback(token)); | |
subscribers = []; | |
} | |
function addSubscriber(callback) { | |
subscribers.push(callback); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment