In this tutorial, I will show you how to work with Axios Interceptors: eject, error, 401 status, handling infinite loop and Refresh Token example.
Related Post:
– Axios request: Get/Post/Put/Delete example
– Axios File Upload example
– React Refresh Token with Axios Interceptors
– React + Redux: Refresh Token with Axios Interceptors
– Vue Refresh Token with Axios Interceptors
– Vue 3 Refresh Token with Axios Interceptors
Contents
Axios interceptors Overview
An Interceptor can be understood as a filter of http requests and responses before they are actually sent or received.
This allows us to manipulate the header, body, parameters of the requests sent to the server as well as check the responses received from the server for the most reasonable.
We can intercept requests or responses before they are handled by then or catch.
// Request interceptor
axios.interceptors.request.use((config) => {...});
// Response interceptor
axios.interceptors.response.use((response) => {...});
Axios interceptors Error
You can also get request errors or response errors in Axios interceptors:
– Request:
axios.interceptors.request.use(
(config) => {
// Do something before request is sent
return config;
},
(error) => {
// Do something with request error
return Promise.reject(error);
});
– Response:
axios.interceptors.response.use(
(response) => { // Any status code from range of 2xx
// Do something with response data
return response;
},
(error) => { // Any status codes outside range of 2xx
// Do something with response error
return Promise.reject(error);
});
Axios interceptors Eject
You can add an Interceptors to an instance of Axios.
const instance = axios.create(...);
const myInterceptor = instance.interceptors.request.use(...);
And then, remove the interceptor:
axios.interceptors.request.eject(myInterceptor);
Axios interceptors for 401 status
If we want to handle 401
status on interceptor response or ANOTHER_STATUS_CODE
, just check error.response.status
like this:
axios.interceptors.response.use(
(response) => {
return res;
},
async (error) => {
if (error.response) {
if (error.response.status === 401) {
// Do something, call refreshToken() request for example;
// return a request
return axios_instance(config);
}
if (error.response.status === ANOTHER_STATUS_CODE) {
// Do something
return Promise.reject(error.response.data);
}
}
return Promise.reject(error);
}
);
Axios interceptor Infinite loop
In case the request is failed again, and the server continue to return 401
status code, it may go to Infinite loop. How to handle this?
We use a flag call _retry
on original Request (config). _retry
is set to true
right after the first time we meet 401
status.
axios.interceptors.response.use(
(response) => {
return res;
},
async (error) => {
const originalConfig = error.config;
if (error.response) {
if (error.response.status === 401 && !originalConfig._retry) {
originalConfig._retry = true;
// Do something, call refreshToken() request for example;
// return a request
return axios_instance(config);
}
if (error.response.status === ANOTHER_STATUS_CODE) {
// Do something
return Promise.reject(error.response.data);
}
}
return Promise.reject(error);
}
);
Axios Interceptors with Refresh Token example
In previous posts, we have implement JWT refresh token on server side:
- Spring Boot JWT Refresh Token example
- Node.js JWT Refresh Token example with MySQL/PostgreSQL
- Node.js JWT Refresh Token example with MongoDB
The diagram shows flow of how we implemented Authentication process with Access Token and Refresh Token.
– A legal JWT
must be added to HTTP Header if Client accesses protected resources.
– A refreshToken
will be provided at the time user signs in.
This is Client that we’re gonna create:
– Login and receive access Token and refresh Token:
– Access resource successfully with accessToken
.
– Continue to access resource with accessToken
but when the server returns response telling that the accessToken
is expired.
Interceptor automatically sends /refreshtoken
request, get new accessToken
.
– Wait for the Refresh Token expired, send a new Request.
Implement Refresh Token using Axios Interceptors
First we create HTML file with following code.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Axios Interceptors - Refresh Token</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
/>
</head>
<body>
<div class="container my-3" style="max-width: 600px">
<h2>Axios Interceptors - Refresh Token</h2>
<div class="card mt-3">
<div class="card-header">Get Tokens</div>
<div class="card-body">
<button class="btn btn-primary" onclick="login()">Login</button>
<button class="btn btn-warning" onclick="clearOutput1()">
Clear
</button>
</div>
<div class="card-body" id="getResult1"></div>
</div>
<div class="card mt-3">
<div class="card-header">Access Data</div>
<div class="card-body">
<button class="btn btn-primary" onclick="getData()">Get Data</button>
<button class="btn btn-warning" onclick="clearOutput2()">
Clear
</button>
</div>
<div class="card-body" id="getResult2"></div>
</div>
<p class="mt-3">
©
<a href="https://www.bezkoder.com" target="_blank">bezkoder.com</a>
</p>
</div>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="main.js"></script>
</body>
</html>
Now we use Axios Interceptors to work with Refresh Token.
main.js
function getLocalAccessToken() {
const accessToken = window.localStorage.getItem("accessToken");
return accessToken;
}
function getLocalRefreshToken() {
const refreshToken = window.localStorage.getItem("refreshToken");
return refreshToken;
}
const instance = axios.create({
baseURL: "http://localhost:8080/api",
headers: {
"Content-Type": "application/json",
},
});
instance.interceptors.request.use(
(config) => {
const token = getLocalAccessToken();
if (token) {
config.headers["x-access-token"] = token;
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
instance.interceptors.response.use(
(res) => {
return res;
},
async (err) => {
const originalConfig = err.config;
if (err.response) {
// Access Token was expired
if (err.response.status === 401 && !originalConfig._retry) {
originalConfig._retry = true;
try {
const rs = await refreshToken();
const { accessToken } = rs.data;
window.localStorage.setItem("accessToken", accessToken);
instance.defaults.headers.common["x-access-token"] = accessToken;
return instance(originalConfig);
} catch (_error) {
if (_error.response && _error.response.data) {
return Promise.reject(_error.response.data);
}
return Promise.reject(_error);
}
}
if (err.response.status === 403 && err.response.data) {
return Promise.reject(err.response.data);
}
}
return Promise.reject(err);
}
);
function signin() {
return instance.post("/auth/signin", {
username: "zkoder",
password: "12345678",
});
}
function refreshToken() {
return instance.post("/auth/refreshtoken", {
refreshToken: getLocalRefreshToken(),
});
}
function getUserContent() {
return instance.get("/test/user");
}
async function login() {
var resultElement = document.getElementById("getResult1");
resultElement.innerHTML = "";
try {
const res = await signin();
const { accessToken, refreshToken } = res.data;
window.localStorage.setItem("accessToken", accessToken);
window.localStorage.setItem("refreshToken", refreshToken);
resultElement.innerHTML =
"<pre>" +
JSON.stringify({ accessToken, refreshToken }, null, 2) +
"</pre>";
} catch (err) {
resultElement.innerHTML = err;
}
}
async function getData() {
var resultElement = document.getElementById("getResult2");
resultElement.innerHTML = "";
try {
const res = await getUserContent();
resultElement.innerHTML =
"<pre>" + JSON.stringify(res.data, null, 2) + "</pre>";
} catch (err) {
resultElement.innerHTML = "<pre>" + JSON.stringify(err, null, 2) + "</pre>";
}
}
function clearOutput1() {
var resultElement = document.getElementById("getResult1");
resultElement.innerHTML = "";
}
function clearOutput2() {
var resultElement = document.getElementById("getResult2");
resultElement.innerHTML = "";
}
Conclusion
Today we’ve known the way to work with Refresh Token using Axios Interceptors. I also show you how to use Axios Interceptors eject, error along with handling 401 status and infinite loop.
You will need back-end code that implements JWT with Refresh Token in one of following tutorials:
- Spring Boot JWT Refresh Token example
- Node.js JWT Refresh Token example with MySQL/PostgreSQL
- Node.js JWT Refresh Token example with MongoDB
You can also apply this in:
– React Refresh Token with Axios Interceptors
– React + Redux: Refresh Token with Axios Interceptors
– Vue Refresh Token with Axios Interceptors
– Vue 3 Refresh Token with Axios Interceptors
Further Reading
– Axios request: Get/Post/Put/Delete example
– Axios File Upload example
– Nodejs Express + React/Angular/Vue:
- Node.js Express + React: JWT Authentication & Authorization example
- Node.js Express + Angular 8: JWT Authentication & Authorization example
- Node.js Express + Angular 10: JWT Authentication & Authorization example
- Node.js Express + Angular 11: JWT Authentication & Authorization example
- Node.js Express + Angular 12: JWT Authentication & Authorization example
- Node.js Express + Angular 13: JWT Authentication & Authorization example
- Node.js Express + Angular 14: JWT Authentication & Authorization example
- Node.js Express + Vue.js: JWT Authentication & Authorization example
– Spring Boot + React/Angular/Vue:
- React + Spring Boot: JWT Authentication & Authorization example
- Angular 8 + Spring Boot: JWT Authentication & Authorization example
- Angular 10 + Spring Boot: JWT Authentication & Authorization example
- Angular 11 + Spring Boot: JWT Authentication & Authorization example
- Angular 12 + Spring Boot: JWT Authentication & Authorization example
- Angular 13 + Spring Boot: JWT Authentication & Authorization example
- Angular 14 + Spring Boot: JWT Authentication & Authorization example
- Vue + Spring Boot: JWT Authentication & Authorization example
All of your tutorials are amazing! Thank you.
If a user tries to access a page and his credentials are expired, how can I save the page so that after the user logs back in, it redirects him?