With previous posts, we’ve known how to build Authentication and Authorization in React.js Application. In this tutorial, I will continue to show you way to implement Refresh Token with JWT and Axios Interceptors in React.
Related Posts:
– Axios Interceptors tutorial with Refresh Token example
– In-depth Introduction to JWT-JSON Web Token
– React JWT Authentication (without Redux) example
– React Hooks: JWT Authentication (without Redux) example
– React + Redux: JWT Authentication example
With Redux: React + Redux: Refresh Token with Axios and JWT example
Contents
React Refresh Token with JWT overview
The diagram shows flow of how we implement React JWT Refresh Token.
– A refreshToken
will be provided at the time user signs in.
– A legal JWT
must be added to HTTP Header if Client accesses protected resources.
– With the help of Axios Interceptors, React App can check if the accessToken
(JWT) is expired (401), sends /refreshToken
request to receive new accessToken
and use it for new resource request.
Let’s see how the React.js Refresh Token works with demo UI.
– First we make an account login.
– Now user can access resources with available Access Token.
– When the Access Token is expired, React automatically send Refresh Token request, receive new Access Token and use it with new request.
– After a period of time, the new Access Token is expired again, and the Refresh Token too.
Now the user cannot access restricted resources.
The Back-end server for this React Client can be found at:
- Spring Boot JWT Refresh Token example
- Node.js JWT Refresh Token example with MySQL/PostgreSQL
- Node.js JWT Refresh Token example with MongoDB
We’re gonna implement Token Refresh feature basing on the code from previous posts, so you need to read one of following tutorials first:
- React JWT Authentication (without Redux) example
- React Hooks: JWT Authentication (without Redux) example
- React + Redux: JWT Authentication example
Axios interceptors in React
Let’s create a service that provides an Axios instance with interceptors
request and response.
services/api.js
import axios from "axios";
import TokenService from "./token.service";
const instance = axios.create({
baseURL: "http://localhost:8080/api",
headers: {
"Content-Type": "application/json",
},
});
instance.interceptors.request.use(
(config) => {
const token = TokenService.getLocalAccessToken();
if (token) {
// config.headers["Authorization"] = 'Bearer ' + token; // for Spring Boot back-end
config.headers["x-access-token"] = token; // for Node.js Express back-end
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
instance.interceptors.response.use(
(res) => {
return res;
},
async (err) => {
const originalConfig = err.config;
if (originalConfig.url !== "/auth/signin" && err.response) {
// Access Token was expired
if (err.response.status === 401 && !originalConfig._retry) {
originalConfig._retry = true;
try {
const rs = await instance.post("/auth/refreshtoken", {
refreshToken: TokenService.getLocalRefreshToken(),
});
const { accessToken } = rs.data;
TokenService.updateLocalAccessToken(accessToken);
return instance(originalConfig);
} catch (_error) {
return Promise.reject(_error);
}
}
}
return Promise.reject(err);
}
);
export default instance;
In the code above, we:
– intercept requests or responses before they are handled by then or catch.
– handle 401
status on interceptor response (except response of login request)
– use a flag call _retry
on original Request (config) to handle Infinite loop. It is the case that request is failed again, and the server continue to return 401
status code.
For more details, please visit:
Axios Interceptors tutorial with Refresh Token example
Update Services with new Axios Interceptors
Axios Interceptors manipulate the header, body, parameters of the requests sent to the server so that we don’t need to add headers
in Axios requests like this:
axios.get(API_URL, { headers: authHeader() })
So we remove auth-header.js file, then update services that use it with new api
service.
services/user.service.js
import api from './api';
class UserService {
getPublicContent() {
return api.get('/test/all');
}
getUserBoard() {
return api.get('/test/user');
}
getModeratorBoard() {
return api.get('/test/mod');
}
getAdminBoard() {
return api.get('/test/admin');
}
}
export default new UserService();
services/auth.service.js
import api from "./api";
import TokenService from "./token.service";
class AuthService {
login(username, password) {
return api
.post("/auth/signin", {
username,
password
})
.then(response => {
if (response.data.accessToken) {
TokenService.setUser(response.data);
}
return response.data;
});
}
logout() {
TokenService.removeUser();
}
register(username, email, password) {
return api.post("/auth/signup", {
username,
email,
password
});
}
getCurrentUser() {
return TokenService.getUser();
}
}
export default new AuthService();
We also need to create TokenService
which Axios instance and other services use above.
TokenService
provides get, set, remove methods to work with Token and User Data stored on Browser.
services/token.service.js
class TokenService {
getLocalRefreshToken() {
const user = JSON.parse(localStorage.getItem("user"));
return user?.refreshToken;
}
getLocalAccessToken() {
const user = JSON.parse(localStorage.getItem("user"));
return user?.accessToken;
}
updateLocalAccessToken(token) {
let user = JSON.parse(localStorage.getItem("user"));
user.accessToken = token;
localStorage.setItem("user", JSON.stringify(user));
}
getUser() {
return JSON.parse(localStorage.getItem("user"));
}
setUser(user) {
console.log(JSON.stringify(user));
localStorage.setItem("user", JSON.stringify(user));
}
removeUser() {
localStorage.removeItem("user");
}
}
export default new TokenService();
React Refresh Token using Hooks
If you use code in React Hooks: JWT Authentication (without Redux) example, you can modify services like this.
services/user.service.js
import api from "./api";
const getPublicContent = () => {
return api.get("/test/all");
};
const getUserBoard = () => {
return api.get("/test/user");
};
const getModeratorBoard = () => {
return api.get("/test/mod");
};
const getAdminBoard = () => {
return api.get("/test/admin");
};
const UserService = {
getPublicContent,
getUserBoard,
getModeratorBoard,
getAdminBoard,
};
export default UserService;
services/auth.service.js
import api from "./api";
import TokenService from "./token.service";
const register = (username, email, password) => {
return api.post("/auth/signup", {
username,
email,
password
});
};
const login = (username, password) => {
return api
.post("/auth/signin", {
username,
password
})
.then((response) => {
if (response.data.accessToken) {
TokenService.setUser(response.data);
}
return response.data;
});
};
const logout = () => {
TokenService.removeUser();
};
const getCurrentUser = () => {
return JSON.parse(localStorage.getItem("user"));
};
const AuthService = {
register,
login,
logout,
getCurrentUser,
};
export default AuthService;
services/token.service.js
const getLocalRefreshToken = () => {
const user = JSON.parse(localStorage.getItem("user"));
return user?.refreshToken;
};
const getLocalAccessToken = () => {
const user = JSON.parse(localStorage.getItem("user"));
return user?.accessToken;
};
const updateLocalAccessToken = (token) => {
let user = JSON.parse(localStorage.getItem("user"));
user.accessToken = token;
localStorage.setItem("user", JSON.stringify(user));
};
const getUser = () => {
return JSON.parse(localStorage.getItem("user"));
};
const setUser = (user) => {
console.log(JSON.stringify(user));
localStorage.setItem("user", JSON.stringify(user));
};
const removeUser = () => {
localStorage.removeItem("user");
};
const TokenService = {
getLocalRefreshToken,
getLocalAccessToken,
updateLocalAccessToken,
getUser,
setUser,
removeUser,
};
export default TokenService;
Conclusion
Today we know how to implement JWT Refresh Token into a React Application using Axios Interceptors. For your understanding the logic flow, you should read one of following tutorials first:
– React JWT Authentication (without Redux) example
– React Hooks: JWT Authentication (without Redux) example
– React + Redux: JWT Authentication example
The Back-end server for this React Client can be found at:
- Spring Boot JWT Refresh Token example
- Node.js JWT Refresh Token example with MySQL/PostgreSQL
- Node.js JWT Refresh Token example with MongoDB
Further Reading
Related Posts:
– In-depth Introduction to JWT-JSON Web Token
– Axios Interceptors tutorial with Refresh Token example
Fullstack Authentication & Authorization:
– React + Spring Boot
– React + Node.js Express
You can simplify import statement with:
Absolute Import in React
Source Code
The source code for this React Application can be found at Github:
– React (Components)
– React (Hooks)
With Redux: React + Redux: Refresh Token with Axios and JWT example
I’ve been following your tutorials recently. Thanks a lot, you greatly help with my thesis and my work.
Hello bezkoder,
Great work done.
I’ve tried implementing this code with django backend. Authentication works fine but the data is not stored in the localstorage and I can’t also see the tokens generated upon successful signin. Please any help will be much appreciated.
Thank you.
I had previously implemented your solution for a normal accesstoken and the application worked wonderfully. So I thought I’d keep on and implement refresh-tokens as well but after following this tutorial I can no longer access the admin site, it just says “No token provided!”.
When doing Console.log(token) inside the verifyToken function inside authJwt.js middleware I get back undefined so something goes wrong with “let token = req.headers[“x-access-token”];” after implementing this.
Any ideas?
Hi, which backend did you use? If my Spring tutorials, you need to work with Authorization on Headers.
I used NodeJS with express!
I’m not too sure what the problem was, but I went to the source code on github and copied the code from there to see if I would get a different result, and now it works like a charm! Thanks for taking your time trying to help me!