Tutorial: React Node Jwt Authentication (without Redux) – using LocalStorage and Axios (plus interceptor) in React application and Express + Sequelize + MySQL/PostgreSQL in Nodejs backend solution.
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. And “How to build Reactjs Nodejs Jwt Token Based Authentication Example?” is one of the most common questions for Nodejs development world. So in the tutorial, I introduce how to implement an application “Reactjs JWT Nodejs token Authentication Example” with details step by step and 100% running sourcecode.
– I give you an Epic of the application, a fullstack excutive flow from frontend (Reactjs) to backend (Nodejs/Express) to database (MySQL/PostgreSQL) with overall architecture diagram.
– I give you a layer diagram of Reactjs Jwt Application with LocalStorage and Axios (plus Interceptor)
– I guide you detail-steps how to implement a security Jwt Token Nodejs backend.
– I guide you step by step how to develop a Reactjs Jwt Authentication application.
– Finally, I do an integrative testing from Reactjs Jwt Authentication application to jwt Nodejs Security RestAPIs.
- Video Guide – How to build React Node Jwt Token Authentication Example
- Overview Reactjs Jwt Nodejs Token Authentication Example
- Token Based Authentication in Node.js RestAPIs Implementation
- Review Nodejs Jwt Architecture Diagram
- Nodejs jwt token Project Goal
- Technologies
- Project Structure
- Create Nodejs Project
- Create Nodejs Sequelize Models
- Nodejs Sequelize Database Configuration
- Define RestAPIs Router with Middleware
- Implement Express RestApis Controller
- Implement Nodejs Server
- Testing Jwt token authentication Nodejs RestAPI
- Reactjs JWT Token Authentication Implementation
- Review Reactjs Architecture Diagram
- Step by step to build Reactjs JWT Authentication Application
- Setup Reactjs Project
- Implement Reactjs JWT Authentication Service
- Implement Reactjs jwt Backend Service with Axios interceptor
- Implement Reactjs jwt AppNavbar component
- Implement Reactjs jwt Home component
- Implement Reactjs jwt SignUp component
- Implement Reactjs jwt Login component
- Implement Reactjs jwt Profile component
- Implement Reactjs jwt token User Page
- Implement Reactjs jwt token PM Page
- Implement Reactjs jwt token Admin Page
- Define Reactjs Router
- Configure URL proxy request
- Integrative Testing – Reactjs JWT Authentication with Nodejs Security
- Further Reading
- Sourcecode
Video Guide – How to build React Node Jwt Token Authentication Example
Overview Reactjs Jwt Nodejs Token Authentication Example
JWT Token Introduction
JSON Web Token (JWT) defines a compact and self-contained way for securely transmitting information between parties as a JSON object.
Scenarios where JSON Web Tokens are useful:
Authorization
: the most common scenario for using JWT. Single Sign On is a feature that widely uses JWTInformation Exchange
: Because JWTs can be signed, JSON Web Tokens are a good way of securely transmitting information between parties.
JSON Web Tokens consist of 3 parts:
- Header
- Payload
- Signature
-> JWT
looks like Header-Base64-String.Payload-Base64-String.Signature-Base64-String
Header consists of two parts:
- token type.
- hashing algorithm.
-> Example:
{
"alg": "HS256",
"typ": "JWT"
}
Payload contains the claims. Claims are statements about an entity and additional information.
There are 3 types of claims ->
Registered claims
-> These are a set of predefined claims: iss (issuer), exp (expiration time), sub (subject)Public claims
Private claims
Example:
{
"sub": "thomasgkz",
"iat": 1537603195,
"exp": 1537689595
}
Signature -> To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.
Example:
HMACSHA512(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
your-256-bit-secret
)
Combine all together, we get 3 Base64-URL strings separated by dots,
-> Example:
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0aG9tYXNna3oiLCJpYXQiOjE1Mzc2MDMxOTUsImV4cCI6MTUzNzY4OTU5NX0.m2YMjTYmOnfR7nnVNxqCzWbQ2FhKRe1eiizxnC2TF4eAoEzKlwo7PheVkKcxj08ST3vB-ZOIhiORvYVfSgzcog
When accessing a protected route or resource, the user agent should send the JWT, typically in the Authorization header using the Bearer schema.
Example:
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0aG9tYXNna3oiLCJpYXQiOjE1Mzc2MDMxOTUsImV4cCI6MTUzNzY4OTU5NX0.m2YMjTYmOnfR7nnVNxqCzWbQ2FhKRe1eiizxnC2TF4eAoEzKlwo7PheVkKcxj08ST3vB-ZOIhiORvYVfSgzcog
Overall Jwt Login System Architecture Diagram

For the Reactjs JWT Authentication tutorial, we have 2 projects:
– Backend project Nodejs/Express provides secured RestAPIs with JWT token.
– Reactjs project will request RestAPIs from Nodejs with the Jwt Token Authentication implementation.
JWT Authentication Sequence Diagram
The diagram below show how our system handles User Registration and User Login processes:

1. User Registration Phase:
– User uses a React.js register form to post user’s info (name, username, email, role, password) to Backend API /api/auth/signup
.
– Backend will check the existing users in database and save user’s signup info to database. Finally, It will return a message (successfully or fail) to
2. User Login Phase:
– User posts user/password to signin to Backend RestAPI /api/auth/signin
.
– Backend will check the username/password, if it is right, Backend will create and JWT string with secret then return it to Reactjs client.
After signin, user can request secured resources from backend server by adding the JWT token in Authorization Header. For each request, backend will check the JWT signature and then returns back the resources based on user’s registered authorities.
Reactjs JWT Authentication Diagram Overview

Reactjs JWT Authentication would be built with 5 main kind blocks:
- Reactjs Router is a standard library for routing in React. It enables the navigation among views of various components in a React Application, allows changing the browser URL, and keeps the UI in sync with the URL.
- Reactjs Components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
- Reactjs Service is a bridge between Reactjs Component and Backend Server, it is used to do technical logic with Backend Server (using Ajax Engine to fetch data from Backend, or using Local Storage to save user login data) and returned a response data to React.js Components
- Local Storage allow to save key/value pairs in a web browser. It is a place to save the login user’s info.
- Axios – (an Ajax Engine) is a promise-based HTTP client for the browser and Node. js. Axios makes it easy to send asynchronous HTTP requests to REST endpoints and perform CRUD operations.
Jwt Nodejs Token Security RestAPIs Diagram Overview

HTTP request that matches route will be accepted by CORS Middleware before coming to Security layer.
Security layer includes:
– JWT Authentication Middleware: verify SignUp, verify token
– Authorization Middleware: check User’s roles
Main Business Logic Processing interacts with database via Sequelize and send HTTP response (token, user information, data based on roles…) to client.
Project Goal
We create a Reactjs JWT Authentication project as below:

It includes 8 components and 2 services and a router in app.js file.
– Home page:

– User Register page:

– Login Page:

– Profile Page:

– Use Page:

– Project Manager Page:

– Reactjs Admin page:

Token Based Authentication in Node.js RestAPIs Implementation
Review Nodejs Jwt Architecture Diagram

Details check the above session: Jwt Nodejs Token Security RestAPIs Diagram Overview
Configure Nodejs/Express Middleware & Restapis
module.exports = function (app) {
const controller = require('../controller/controller.js');
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "x-access-token, Origin, Content-Type, Accept");
next();
});
app.post('/api/auth/signup', [verifySignUp.checkDuplicateUserNameOrEmail, verifySignUp.checkRolesExisted], controller.signup);
app.post('/api/auth/signin', controller.signin);
app.get('/api/test/user', [authJwt.verifyToken], controller.userContent);
app.get('/api/test/pm', [authJwt.verifyToken, authJwt.isPmOrAdmin], controller.managementBoard);
app.get('/api/test/admin', [authJwt.verifyToken, authJwt.isAdmin], controller.adminBoard);
}
– For HTTP Header, we allow x-access-token
for JWT.
– When a HTTP request call /signup
api, it will also be passed to checkDuplicateUserNameOrEmail()
and checkRolesExisted()
funtions before going to controller’s signup()
funtion.
– JWT Authentication middleware with verifyToken()
and role checking funtions (isPmOrAdmin, isAdmin) will be called before controller returns authorized data (based on roles).
Jwt Nodejs Generate Token
Inside controller’s signin()
funtion, we use sign()
funtion from jsonwebtoken
:
var jwt = require('jsonwebtoken');
exports.signin = (req, res) => {
User.findOne({
where: { username: req.body.username }
}).then(user => {
// check user & password...
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400 // expires in 24 hours
});
// get other user information
res.status(200).send({
auth: true,
accessToken: token,
username: user.username,
authorities: authorities
});
});
}
Nodejs Jwt Verify Token
We get token from x-access-token
of HTTP headers, then use verify()
function of jsonwebtoken
:
const jwt = require('jsonwebtoken');
verifyToken = (req, res, next) => {
let token = req.headers['x-access-token'];
if (!token){ // notice that no token was provided...}
jwt.verify(token, 'SECRET KEY', (err, decoded) => {
if (err){
return res.status(500).send({
auth: false,
message: 'Fail to Authentication. Error -> ' + err
});
}
req.userId = decoded.id;
next();
});
}
Jwt Nodejs User & Roles Relationship model
We define Role
& User
Sequelize models as below:

Implementation of the Many-to-Many relationship:
// user.model.js
module.exports = (sequelize, Sequelize) => {
const User = sequelize.define('users', {
firstname: {
type: Sequelize.STRING
},
lastname: {
type: Sequelize.STRING
},
username: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
}
});
return User;
}
// role.model.js
module.exports = (sequelize, Sequelize) => {
const Role = sequelize.define('roles', {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
name: {
type: Sequelize.STRING
}
});
return Role;
}
// db.config.js
const Sequelize = require('sequelize');
const sequelize = new Sequelize(...);
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
db.user = require('../model/user.model.js')(sequelize, Sequelize);
db.role = require('../model/role.model.js')(sequelize, Sequelize);
db.role.belongsToMany(db.user, { through: 'user_roles', foreignKey: 'roleId', otherKey: 'userId'});
db.user.belongsToMany(db.role, { through: 'user_roles', foreignKey: 'userId', otherKey: 'roleId'});
module.exports = db;
Nodejs jwt token Project Goal
The diagram below show how our system handles User Registration and User Login processes:

– SignUp /api/auth/signup
:

– Sign In /api/auth/signin
:

– Access User Page /api/test/user
:

– Access PM Page /api/test/pm
:

– Access to Admin page /api/test/admin
:

Technologies
– Nodejs/Express
– Json Web Token
– BCryptjs
– Sequelize
– MySQL
Nodejs Jwt Token Project Structure

– config
package defines MySQL Database Configuration, JWT Secret Key & User Roles.
– model
package defines Role & User Sequelize models.
– router
package defines RestAPI URLs, verification functions for signup api, JWT verification for signin api, and authorization functions for content requested by user roles.
– controller
package defines process functions for each RestAPIs declared in router package.
Create Nodejs Project
Install Express, Sequelize, MySQL, Json Web Token, Bcryptjs:
$npm install express sequelize mysql2 jsonwebtoken bcryptjs --save
– package.json
{
"name": "nodejs-jwt-authentication",
"version": "1.0.0",
"description": "Nodejs JWT Authentication project",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"Nodejs",
"JWT",
"Authentication",
"Express",
"RestAPIs"
],
"author": "https://loizenjava.com",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mysql2": "^2.1.0",
"sequelize": "^5.21.12"
}
}
Create Nodejs Sequelize Models
– model/user.model.js
module.exports = (sequelize, Sequelize) => {
const User = sequelize.define('users', {
lastname: {
type: Sequelize.STRING
},
firstname: {
type: Sequelize.STRING
},
username: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
}
});
return User;
}
– model/role.model.js
module.exports = (sequelize, Sequelize) => {
const Role = sequelize.define('roles', {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
name: {
type: Sequelize.STRING
}
});
return Role;
}
Nodejs Sequelize Database Configuration
– config/env.js
For MySQL database:
const env = {
database: 'loizenjavadb',
username: 'root',
password: '12345',
host: 'localhost',
dialect: 'mysql',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
};
module.exports = env;
For PostgreSQL database:
const env = {
database: 'loizenjava',
username: 'postgres',
password: '123',
host: 'localhost',
dialect: 'postgres',
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
};
module.exports = env;
Define RestAPIs Router with Middleware
Nodejs RestAPIs Router
– router/router.js
const verifySignUp = require('./verifySignUp');
const authJwt = require('./verifyJwtToken');
module.exports = function (app) {
const controller = require('../controller/controller.js');
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "x-access-token, Origin, Content-Type, Accept");
next();
});
app.post('/api/auth/signup', [verifySignUp.checkDuplicateUserNameOrEmail, verifySignUp.checkRolesExisted], controller.signup);
app.post('/api/auth/signin', controller.signin);
app.get('/api/test/user', [authJwt.verifyToken], controller.userContent);
app.get('/api/test/pm', [authJwt.verifyToken, authJwt.isPmOrAdmin], controller.managementBoard);
app.get('/api/test/admin', [authJwt.verifyToken, authJwt.isAdmin], controller.adminBoard);
}
Nodejs/Express Middleware functions
– router/verifySignUp.js
const db = require('../config/db.config.js');
const config = require('../config/config.js');
const ROLEs = config.ROLEs;
const User = db.user;
checkDuplicateUserNameOrEmail = (req, res, next) => {
// -> Check Username is already in use
User.findOne({
where: {
username: req.body.username
}
}).then(user => {
if (user) {
res.status(400).send("Fail -> Username is already taken!");
return;
}
// -> Check Email is already in use
User.findOne({
where: {
email: req.body.email
}
}).then(user => {
if (user) {
res.status(400).send("Fail -> Email is already in use!");
return;
}
next();
});
});
}
checkRolesExisted = (req, res, next) => {
for (let i = 0; i < req.body.roles.length; i++) {
if (!ROLEs.includes(req.body.roles[i].toUpperCase())) {
res.status(400).send("Fail -> Does NOT exist Role = " + req.body.roles[i]);
return;
}
}
next();
}
const signUpVerify = {};
signUpVerify.checkDuplicateUserNameOrEmail = checkDuplicateUserNameOrEmail;
signUpVerify.checkRolesExisted = checkRolesExisted;
module.exports = signUpVerify;
– router/verifyJwtToken.js
const jwt = require('jsonwebtoken');
const config = require('../config/config.js');
const db = require('../config/db.config.js');
const User = db.user;
verifyToken = (req, res, next) => {
let token = req.headers['x-access-token'];
if (!token){
return res.status(403).send({
auth: false, message: 'No token provided.'
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err){
return res.status(500).send({
auth: false,
message: 'Fail to Authentication. Error -> ' + err
});
}
req.userId = decoded.id;
next();
});
}
isAdmin = (req, res, next) => {
User.findById(req.userId)
.then(user => {
user.getRoles().then(roles => {
for(let i=0; i<roles.length; i++){
console.log(roles[i].name);
if(roles[i].name.toUpperCase() === "ADMIN"){
next();
return;
}
}
res.status(403).send("Require Admin Role!");
return;
})
})
}
isPmOrAdmin = (req, res, next) => {
User.findById(req.userId)
.then(user => {
user.getRoles().then(roles => {
for(let i=0; i<roles.length; i++){
if(roles[i].name.toUpperCase() === "PM"){
next();
return;
}
if(roles[i].name.toUpperCase() === "ADMIN"){
next();
return;
}
}
res.status(403).send("Require PM or Admin Roles!");
})
})
}
const authJwt = {};
authJwt.verifyToken = verifyToken;
authJwt.isAdmin = isAdmin;
authJwt.isPmOrAdmin = isPmOrAdmin;
module.exports = authJwt;
Implement Express RestApis Controller
controller/controller.js
const db = require('../config/db.config.js');
const config = require('../config/config.js');
const User = db.user;
const Role = db.role;
const Op = db.Sequelize.Op;
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
exports.signup = (req, res) => {
// Save User to Database
User.create({
name: req.body.name,
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8)
}).then(user => {
Role.findAll({
where: {
name: {
[Op.or]: req.body.roles
}
}
}).then(roles => {
user.setRoles(roles).then(() => {
res.send({ message: 'Registered successfully!' });
});
}).catch(err => {
res.status(500).send({ reason: err.message });
});
}).catch(err => {
res.status(500).send({ reason: err.message });
})
}
exports.signin = (req, res) => {
User.findOne({
where: {
username: req.body.username
}
}).then(user => {
if (!user) {
return res.status(404).send({ reason: 'User Not Found.' });
}
var passwordIsValid = bcrypt.compareSync(req.body.password, user.password);
if (!passwordIsValid) {
return res.status(401).send({ auth: false, accessToken: null, reason: 'Invalid Password!' });
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400 // expires in 24 hours
});
var authorities = [];
user.getRoles().then(roles => {
for (let i = 0; i < roles.length; i++) {
authorities.push('ROLE_' + roles[i].name.toUpperCase());
}
res.status(200).send({
auth: true,
accessToken: token,
username: user.username,
authorities: authorities
});
})
}).catch(err => {
res.status(500).send({ reason: err.message });
});
}
exports.userContent = (req, res) => {
User.findOne({
where: { id: req.userId },
attributes: ['name', 'username', 'email'],
include: [{
model: Role,
attributes: ['id', 'name'],
through: {
attributes: ['userId', 'roleId'],
}
}]
}).then(user => {
res.status(200).send({
'description': '>>> User Contents!',
'user': user
});
}).catch(err => {
res.status(500).send({
'description': 'Can not access User Page',
'error': err
});
})
}
exports.adminBoard = (req, res) => {
User.findOne({
where: { id: req.userId },
attributes: ['name', 'username', 'email'],
include: [{
model: Role,
attributes: ['id', 'name'],
through: {
attributes: ['userId', 'roleId'],
}
}]
}).then(user => {
res.status(200).send({
'description': '>>> Admin Contents',
'user': user
});
}).catch(err => {
res.status(500).send({
'description': 'Can not access Admin Board',
'error': err
});
})
}
exports.managementBoard = (req, res) => {
User.findOne({
where: { id: req.userId },
attributes: ['name', 'username', 'email'],
include: [{
model: Role,
attributes: ['id', 'name'],
through: {
attributes: ['userId', 'roleId'],
}
}]
}).then(user => {
res.status(200).send({
'description': '>>> Project Management Board',
'user': user
});
}).catch(err => {
res.status(500).send({
'description': 'Can not access Management Board',
'error': err
});
})
}
We define jwt-secret-key
& User Roles in config/config.js
:
module.exports = {
'secret': 'loizenjava-super-secret-key',
ROLEs: ['USER', 'ADMIN', 'PM']
};
Implement Nodejs Server
– server.js
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.json())
require('./app/router/router.js')(app);
const db = require('./app/config/db.config.js');
const Role = db.role;
// force: true will drop the table if it already exists
db.sequelize.sync({force: true}).then(() => {
console.log('Drop and Resync with { force: true }');
initial();
});
// Create a Server
var server = app.listen(8080, function () {
var host = server.address().address
var port = server.address().port
console.log("App listening at http://%s:%s", host, port)
})
function initial() {
Role.create({
id: 1,
name: "USER"
});
Role.create({
id: 2,
name: "PM"
});
Role.create({
id: 3,
name: "ADMIN"
});
}
Testing Jwt token authentication Nodejs RestAPI
Sign-Up 3 users:
– Jack has ROLE_USER
role
– Adam has ROLE_PM
& ROLE_USER
roles
– Thomas has ROLE_ADMIN
role

– Check database’s tables:

Signin with normal user
– Jack can access api/test/user url, can NOT access others.
-> Sign In:

Access Protected Resources:


Signin with PM user
– Adam can access api/test/user and api/test/pm url.
Can NOT access /api/test/admin url.
-> Sign In:

-> Access Protected Resources:



Signin with Admin user
– Thomas can access all URLs.
-> Sign In:

-> Access Protected Resource:

Reactjs JWT Token Authentication Implementation
Review Reactjs Login Architecture Diagram

More details you can see more at above session: Reactjs JWT Authentication Diagram Overview
Step by step to build Reactjs JWT Authentication Application
>>> image
For building the Reactjs JWT Authentication, we do below steps:
- We create Reactjs Jwt Authentication application
- We implement React.js Authentication Service. It provides RestAPIs to signin/signup and retrieve user’s login info from Local Storage
- We implement React.js Backend Service. It provides RestAPIs to retrieve data from Security Backend
- We implement Reactjs components to signIn/signUp and show data from backend server
- We define a Reactjs router to navigate between UI components
Setup Reactjs Project
Create React App is a command line utility that generates React projects for you. It’s a convenient tool because it also offers commands that will build and optimize your project for production.
The create-react-app
will set up everything you need to run a React application.
– Create a new project in the app directory with Yarn.
yarn create react-app Reactjs-Jwt-Authentication
Project Structure:

More details you can see at: Create Reactjs Project
After the app creation process completes, navigate into the app directory and install Bootstrap, React Router, and Reactstrap.
– Reactstrap: This library contains React Bootstrap 4 components that favor composition and control. The library does not depend on jQuery or Bootstrap javascript.
– React Router: Components are the heart of React’s powerful, declarative programming model. React Router is a collection of navigational components that compose declaratively with your application.
cd Reactjs-Jwt-Authentication
yarn add bootstrap react-cookie react-router-dom reactstrap
Implement Reactjs JWT Authentication Service
The service AuthenticationService
implements 4 main functions to signup
/signin
/signout
and get current login user’s info:
To do http requests with Backend server, the AuthenticationService
use Axios (an HttpClient) to interact with Server. AuthenticationService
uses localStorage
to store user login’s info.
import axios from "axios";
/**
* @Copyright by https://loizenjava.com
* youtube loizenjava
*/
class AuthenticationService {
signin = (username, password) => {
return axios.post("/api/auth/signin", {username, password})
.then(response => {
if (response.data.accessToken) {
localStorage.setItem("user", JSON.stringify(response.data));
}
return response.data;
})
.catch(err => {
console.log(err);
throw err;
});
}
signOut() {
localStorage.removeItem("user");
}
register = async(firstname, lastname, username, email, password) => {
return axios.post("/api/auth/signup", {
firstname,
lastname,
username,
email,
password
});
}
getCurrentUser() {
return JSON.parse(localStorage.getItem('user'));;
}
}
export default new AuthenticationService();
Implement Reactjs jwt Backend Service with Axios interceptor
BackendService
is used to get resources from server:
– getUserBoard()
– getPmBoard()
– getAdminBoard()
With each request from BackendService
to server, we use axios interceptors to attach the Authorization
header with JWT token.
import axios from 'axios';
// Add a request interceptor
axios.interceptors.request.use( config => {
const user = JSON.parse(localStorage.getItem('user'));
if(user && user.accessToken){
const token = 'Bearer ' + user.accessToken;
config.headers.Authorization = token;
}
return config;
});
class BackendService {
async getUserBoard() {
return await axios.get("/api/test/user");
}
async getPmBoard() {
return await axios.get("/api/test/pm");
}
async getAdminBoard() {
return await axios.get("/api/test/admin");
}
}
export default new BackendService();
Implement Reactjs jwt AppNavbar component

import React, { Component } from 'react';
import { Collapse, Nav, Navbar, NavbarBrand, NavbarToggler, NavbarText, NavItem, NavLink } from 'reactstrap';
import { Link } from 'react-router-dom';
import { withRouter } from 'react-router-dom';
import AuthenticationService from '../services/AuthenticationService';
class AppNavbar extends Component {
constructor(props) {
super(props);
this.state = {isOpen: false};
this.toggle = this.toggle.bind(this);
this.state = {
showUser: false,
showPM: false,
showAdmin: false,
username: undefined,
login: false
};
}
componentDidMount() {
const user = AuthenticationService.getCurrentUser();
if (user) {
const roles = [];
user.authorities.forEach(authority => {
roles.push(authority.authority)
});
this.setState({
showUser: true,
showPM: roles.includes("ROLE_PM") || roles.includes("ROLE_ADMIN"),
showAdmin: roles.includes("ROLE_ADMIN"),
login: true,
username: user.username
});
}
}
signOut = () => {
AuthenticationService.signOut();
this.props.history.push('/home');
window.location.reload();
}
toggle() {
this.setState({
isOpen: !this.state.isOpen
});
}
render() {
return <Navbar color="dark" dark expand="md">
<NavbarBrand tag={Link} to="/home">Loizenai.com</NavbarBrand>
<Nav className="mr-auto">
<NavLink href="/home">Home</NavLink>
{this.state.showUser && <NavLink href="/user">User</NavLink>}
{this.state.showPM && <NavLink href="/pm">PM</NavLink>}
{this.state.showAdmin && <NavLink href="/admin">Admin</NavLink>}
</Nav>
<NavbarToggler onClick={this.toggle}/>
<Collapse isOpen={this.state.isOpen} navbar>
{
this.state.login ? (
<Nav className="ml-auto" navbar>
<NavItem>
<NavbarText>
Signed in as: <a href="/profile">{this.state.username}</a>
</NavbarText>
</NavItem>
<NavItem>
<NavLink href="#" onClick={this.signOut}>SignOut</NavLink>
</NavItem>
</Nav>
) : (
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink href="/signin">Login</NavLink>
</NavItem>
<NavItem>
<NavLink href="/signup">SignUp</NavLink>
</NavItem>
</Nav>
)
}
</Collapse>
</Navbar>;
}
}
export default withRouter(AppNavbar);
– In AppNavbar
component, We use componentDidMount()
to load user info, and then extracts data from user login info to determine what links would be showed on React.js’s UI.
Implement Reactjs jwt Home component

import React, { Component } from 'react';
import AppNavbar from './AppNavbar';
import { Link } from 'react-router-dom';
import { Button, Container } from 'reactstrap';
import { Alert } from "react-bootstrap"
class Home extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
}
render() {
return (
<div>
<AppNavbar/>
<Container fluid>
<div style={{marginTop:"20px"}}>
<Alert variant="primary">
<h2>Reactjs JWT Authentication Application</h2>
<Button color="success"><Link to="/signin"><span style={{color:"white"}}>Login</span></Link></Button>
</Alert>
</div>
</Container>
</div>
);
}
}
export default Home;
Implement Reactjs jwt SignUp component

– For posting data from register-form to backend server, SignUp component uses the register(...)
function of AuthenticationService
service.
– SignUp
component implements a changeHandler()
function to save the values from input fields of Register form to the state object of SignUp
component.
– The function changeHandler()
also includes segment code to validate input data from register-form:

– Detail Coding:
import React, { Component } from 'react';
import AppNavbar from './AppNavbar';
import { Container } from 'reactstrap';
import { Button, Form, FormGroup, Input, Label, Row, Col } from "reactstrap";
import { Alert } from "react-bootstrap"
import Authentication from '../services/AuthenticationService'
const validEmailRegex = RegExp(/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i);
const validateForm = (errors) => {
let valid = true;
Object.values(errors).forEach(
(val) => val.length > 0 && (valid = false)
);
return valid;
}
class SignUp extends Component {
constructor(props) {
super(props);
this.state = {
firstname: "",
lastname: "",
username: "",
email: "",
password: "",
message: "",
successful: false,
validForm: true,
errors: {
firstname: '',
lastname: '',
username: '',
email: '',
password: ''
}
};
}
changeHandler = (event) => {
const { name, value } = event.target;
let errors = this.state.errors;
switch (name) {
case 'firstname':
errors.firstname =
value.length < 3
? 'FirstName must be 3 characters long!'
: '';
break;
case 'lastname':
errors.lastname =
value.length < 3
? 'LastName must be 3 characters long!'
: '';
break;
case 'username':
errors.username =
value.length < 5
? 'Username must be 5 characters long!'
: '';
break;
case 'email':
errors.email =
validEmailRegex.test(value)
? ''
: 'Email is not valid!';
break;
case 'password':
errors.password =
value.length < 8
? 'Password must be 8 characters long!'
: '';
break;
default:
break;
}
this.setState({errors, [name]: value}, ()=> {
console.log(errors)
})
}
signUp = (e) => {
e.preventDefault();
const valid = validateForm(this.state.errors);
this.setState({validForm: valid});
if(valid){
Authentication.register(
this.state.firstname,
this.state.lastname,
this.state.username,
this.state.email,
this.state.password
).then(
response => {
this.setState({
message: response.data.message,
successful: true
});
},
error => {
console.log("Fail! Error = " + error.toString());
this.setState({
successful: false,
message: error.toString()
});
}
);
}
}
render() {
const title = <h2>Register User</h2>;
const errors = this.state.errors;
let alert = "";
if(this.state.message){
if(this.state.successful){
alert = (
<Alert variant="success">
{this.state.message}
</Alert>
);
}else{
alert = (
<Alert variant="danger">
{this.state.message}
</Alert>
);
}
}
return (
<div>
<AppNavbar/>
<Container fluid>
<Row>
<Col sm="12" md={{ size: 4, offset: 4 }}>
{title}
<Form onSubmit={this.signUp}>
<FormGroup controlId="forFirstname">
<Label for="firstname">First Name</Label>
<Input
type="text"
placeholder="Enter First Name"
name="firstname" id="firstname"
value={this.state.firstname}
autoComplete="firstname"
onChange={this.changeHandler}
/>
{
errors.firstname && (
<Alert variant="danger">
{errors.firstname}
</Alert>
)
}
</FormGroup>
<FormGroup controlId="forLastname">
<Label for="lastname">Last Name</Label>
<Input
type="text"
placeholder="Enter Last Name"
name="lastname" id="lastname"
value={this.state.lastname}
autoComplete="lastname"
onChange={this.changeHandler}
/>
{
errors.lastname && (
<Alert variant="danger">
{errors.firstname}
</Alert>
)
}
</FormGroup>
<FormGroup controlId="forUsername">
<Label for="username">Username</Label>
<Input
type="text"
placeholder="Enter UserName"
name="username" id="username"
value={this.state.username}
autoComplete="username"
onChange={this.changeHandler}
/>
{
errors.username && (
<Alert variant="danger">
{errors.username}
</Alert>
)
}
</FormGroup>
<FormGroup controlId="formEmail">
<Label for="email">Email</Label>
<Input required
type="text"
placeholder="Enter Email"
name="email" id="email"
value={this.state.email}
autoComplete="email"
onChange={this.changeHandler}
/>
{
errors.email && (
<Alert variant="danger">
{errors.email}
</Alert>
)
}
</FormGroup>
<FormGroup controlId="formPassword">
<Label for="password">Password</Label>
<Input required
type="password"
placeholder="Enter Password"
name="password" id="password"
value={this.state.password}
autoComplete="password"
onChange={this.changeHandler}
/>
{
errors.password && (
<Alert key="errorspassword" variant="danger">
{errors.password}
</Alert>
)
}
</FormGroup>
<Button variant="primary" type="submit">
Create
</Button>
{
!this.state.validForm && (
<Alert key="validForm" variant="danger">
Please check the inputs again!
</Alert>
)
}
{alert}
</Form>
</Col>
</Row>
</Container>
</div>);
}
}
export default SignUp;
Implement Reactjs jwt Login component

– Login
component implement a function doLogin
that uses a function signin()
of AuthenticationService
service to signin to secured Backend server with Jwt token.
import React, { Component } from 'react';
import AppNavbar from './AppNavbar';
import { Container } from 'reactstrap';
import { Form, Alert, FormGroup, Input, Label, Row, Col } from "reactstrap";
import {Button} from 'react-bootstrap';
import AuthenticationService from "../services/AuthenticationService";
import avatar from '../../avatar.png';
import '../../App.css';
class Login extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
error: ""
};
}
changeHandler = (event) => {
let nam = event.target.name;
let val = event.target.value;
this.setState({[nam]: val});
}
doLogin = async (event) => {
event.preventDefault();
AuthenticationService
.signin(this.state.username,
this.state.password)
.then(
() => {
this.props.history.push('/profile');
},
error => {
console.log("Login fail: error = { " + error.toString() + " }");
this.setState({error: "Can not signin successfully ! Please check username/password again"});
}
);
}
render() {
return (
<div>
<AppNavbar/>
<Container fluid>
<Row style={{marginTop:"20px"}}>
<Col sm="12" md={{ size: 3, offset: 4 }}>
<div style={{marginBottom: "10px"}}>
<img src={avatar} alt="Avatar" className="avatar center"
style={{width: "50%", height: "auto"}}/>
</div>
<Form onSubmit={this.doLogin}>
<FormGroup>
<Label for="username"><strong>Username</strong></Label>
<Input autoFocus
type="text"
name="username" id="username"
value={this.state.username}
placeholder="Enter Username"
autoComplete="username"
onChange={this.changeHandler}
/>
</FormGroup>
<FormGroup>
<Label for="password"><strong>Password</strong></Label>
<Input type="password"
name="password" id="password"
value={this.state.password}
placeholder="Enter Password"
autoComplete="password"
onChange={this.changeHandler}
/>
</FormGroup>
<Button type="submit" variant="primary" size="lg" block>
Sign In
</Button>
{
this.state.error && (
<Alert color="danger">
{this.state.error}
</Alert>
)
}
</Form>
</Col>
</Row>
</Container>
</div>);
}
}
export default Login;
Implement Reactjs jwt Profile component
Profile
component just uses a function componentDidMount()
that calls a function getCurrentUser()
of AuthenticationService
service to get the current user login’s info and shows them on UI.

import React, { Component } from 'react';
import AppNavbar from './AppNavbar';
import { Link } from 'react-router-dom';
import { Button, Container } from 'reactstrap';
import { Alert } from "react-bootstrap"
import AuthenticationService from '../services/AuthenticationService';
class Profile extends Component {
constructor(props) {
super(props);
this.state = {user: undefined};
}
componentDidMount() {
const user = AuthenticationService.getCurrentUser();
this.setState({user: user});
}
render() {
let userInfo = "";
const user = this.state.user;
// login
if (user && user.accessToken) {
let roles = "";
user.authorities.forEach(authority => {
roles = roles + " " + authority.authority
});
userInfo = (
<div style={{marginTop:"20px"}}>
<Alert variant="info">
<h2>User Info</h2>
<ul>
<li>Username: {user.username}</li>
<li>Access Token: {user.accessToken}</li>
<li>Authorities: {roles}</li>
</ul>
</Alert>
</div>
);
} else { // not login
userInfo = <div style={{marginTop:"20px"}}>
<Alert variant="primary">
<h2>Profile Component</h2>
<Button color="success"><Link to="/signin"><span style={{color:"white"}}>Login</span></Link></Button>
</Alert>
</div>
}
return (
<div>
<AppNavbar/>
<Container fluid>
{userInfo}
</Container>
</div>
);
}
}
export default Profile;
Implement Reactjs jwt token User Page

In the componentDidMount()
function, the component UserPage
uses the service BackendService
to load user-content from secured backend-server and show it on UI.
import AppNavbar from './AppNavbar';
import React, { Component } from 'react';
import { Container } from 'reactstrap';
import BackendService from '../services/BackendService';
import { Alert } from "react-bootstrap"
class UserPage extends Component {
constructor(props) {
super(props);
this.state={
content: "",
error: ""
}
}
componentDidMount() {
BackendService.getUserBoard()
.then( response => {
this.setState({content: response.data})
} , error => {
console.log(error);
this.setState({
error: error.toString()
});
});
}
render() {
return (
<div>
<AppNavbar/>
<Container fluid>
{
this.state.content ? (
<div style={{marginTop: "20px"}}>
<Alert variant="info">
<h2>{this.state.content}</h2>
</Alert>
</div>
) : (
<div style={{marginTop: "20px"}}>
<Alert variant="danger">
{this.state.error}
</Alert>
</div>
)
}
</Container>
</div>
);
}
}
export default UserPage;
Implement Reactjs jwt token PM Page

In the componentDidMount()
function, the component ProjectManagerPage
uses the service BackendService
to load pm-content from secured backend-server and show it on UI.
import AppNavbar from './AppNavbar';
import React, { Component } from 'react';
import { Container } from 'reactstrap';
import { Alert } from "reactstrap";
import BackendService from '../services/BackendService';
class ProjectManagerPage extends Component {
constructor(props) {
super(props);
this.state={
content: "",
error: ""
}
}
componentDidMount() {
BackendService.getPmBoard()
.then( response => {
this.setState({
content: response.data
})
} , error => {
console.log(error);
this.setState({
error: error.toString()
});
});
}
render() {
return (
<div>
<AppNavbar/>
<Container fluid>
{
this.state.content ? (
<div style={{marginTop: "20px"}}>
<Alert color="info">
<h2>{this.state.content}</h2>
</Alert>
</div>
) : (
<div style={{marginTop: "20px"}}>
<Alert color="danger">
{this.state.error}
</Alert>
</div>
)
}
</Container>
</div>
);
}
}
export default ProjectManagerPage;
Implement Reactjs jwt token Admin Page

In the componentDidMount()
function, the component AdminPage
uses the service BackendService
to load admin-content from secured backend-server and show it on UI.
import AppNavbar from './AppNavbar';
import React, { Component } from 'react';
import { Container } from 'reactstrap';
import { Alert } from "reactstrap";
import BackendService from '../services/BackendService';
class AdminPage extends Component {
constructor(props) {
super(props);
this.state={
content: "",
error: ""
}
}
componentDidMount() {
BackendService.getAdminBoard()
.then( response => {
this.setState({
content: response.data
})
} , error => {
console.log(error);
this.setState({
error: error.toString()
});
});
}
render() {
return (
<div>
<AppNavbar/>
<Container fluid>
{
this.state.content ? (
<div style={{marginTop: "20px"}}>
<Alert variant="info">
<h2>{this.state.content}</h2>
</Alert>
</div>
) : (
<div style={{marginTop: "20px"}}>
<Alert variant="danger">
{this.state.error}
</Alert>
</div>
)
}
</Container>
</div>
);
}
}
export default AdminPage;
Define Reactjs Router
App.js
uses React Router to navigate between components:
- path “/” and “/home” is mapped with
Home
component - path “/profile” is mapped with
Profile
component - path “/user” is mapped with
UserPage
component - path “/pm” is mapped with
ProjectManagerPage
component - path “/admin” is mapped with
Admin
component - path “/signin” is mapped with
Login
component - path “/signup” is mapped with
SignUp
component
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import './App.css';
import Home from './app/components/Home';
import Profile from './app/components/Profile';
import UserPage from './app/components/UserPage';
import ProjectManagerPage from './app/components/ProjectManagerPage';
import SignUp from './app/components/SignUp';
import AdminPage from './app/components/AdminPage';
import Login from './app/components/Login';
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route path='/' exact={true} component={Home}/>
<Route path='/home' exact={true} component={Home}/>
<Route path='/profile' exact={true} component={Profile}/>
<Route path='/user' exact={true} component={UserPage}/>
<Route path='/pm' exact={true} component={ProjectManagerPage}/>
<Route path='/admin' exact={true} component={AdminPage}/>
<Route path='/signin' exact={true} component={Login}/>
<Route path='/signup' exact={true} component={SignUp}/>
</Switch>
</Router>
)
}
}
export default App;
Configure URL proxy request
To proxy from /api to http://localhost:8080/api, add a proxy setting to app/package.json.
"scripts": {...},
"proxy": "http://localhost:8080",
Integrative Testing – Reactjs JWT Authentication with Nodejs Security
– Start Backend Server at port 8080.
– Start Reactjs application with cmd: yarn start
Testcase 1 – Reactjs JWT SignUp Nodejs RestAPI

– Check MySQL database:

Testcase 2 – Reactjs JWT Login Nodejs RestAPI with user role

Then re-login with right username/password: jack-loizenjava.com/123456789.
-> after signin successfully, Reactjs application will be redirected to Profile component:

– Get User content:

Testcase 3 – Reactjs JWT SignOut Nodejs RestAPI
To signout, just click to the signout link at the most right side of Navigation-Bar, after signout successfully, Reactjs application will be redirected to Home page.

Testcase 4 – Reactjs JWT SignIn Nodejs RestAPI with other roles
1. Register a Adam user, with PM_ROLE and USER_ROLE:

– Check MySQL:

– Adam logins successfully with below user login’s info:

2. Register Thomas user, with ADMIN_ROLE:

– Check MySQL:

– Access the admin-content:


Further Reading
– See LocalStorage object:

Sourcecode
Full sourcecode: “Reactjs Jwt Nodejs/Express Token Authentication Example – React.js Spring Security Login”
1. Reactjs Frontend:
reactjs-jwt-token-authentication
Github sourceode:
reactjs-jwt-authentication-github
2. Jwt Nodejs/Express Token Authentication Backend:
jwt-springboot-reactjs-token-authentication-example
Github sourcode: