Nodejs JWT Authentication - Nodejs/Express RestAPIs + JSON Web Token + BCryptjs + Sequelize + MySQL
Tags: node, jwt, authentication, express
Published: 2021-03-10 17:12:52

https://ozenero.com/vue-js-spring-boot-example-spring-data-jpa-rest-mariadb-crud-example

JSON Web Token defines a compact and self-contained way for securely transmitting information as a JSON object.
In the tutorial, we show how to build a Nodejs Token Authentication RestAPIs with JSON Web Token (JWT).

Related posts:
- <a href="https://grokonez.com/node-js/sequelize-many-to-many-association-nodejs-express-mysql">Sequelize Many-to-Many association – NodeJS/Express, MySQL</a>
- <a href="https://grokonez.com/node-js/sequelize-orm-build-crud-restapis-with-nodejs-express-sequelize-mysql">Sequelize ORM – Build CRUD RestAPIs with NodeJs/Express, Sequelize, MySQL</a>
- Fullstack with Angular: <a href="https://grokonez.com/node-js/angular-nodejs-jwt-authentication-fullstack-nodejs-express-restapis-jwt-bcryptjs-sequelize-mysql-part-1-overview-and-architecture">Angular & Nodejs JWT Authentication fullstack</a>

<!--more-->
<h2 id="technologies">Technologies</h2>
- Nodejs/Express
- Json Web Token
- BCryptjs
- Sequelize
- MySQL
<h2>JSON Web Token</h2>
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:
<ul>
<li><strong>Authorization</strong>: the most common scenario for using JWT. Single Sign On is a feature that widely uses JWT</li>
<li><strong>Information Exchange</strong>: Because JWTs can be signed, JSON Web Tokens are a good way of securely transmitting information between parties.</li>
</ul>

JSON Web Tokens consist of 3 parts:
<ul>
<li>Header</li>
<li>Payload</li>
<li>Signature</li>
</ul>

-> <code>JWT</code> looks like <code>Header-Base64-String.Payload-Base64-String.Signature-Base64-String</code>

<strong>Header</strong>	consists of two parts:
<ul>
<li>token type.</li>
<li>hashing algorithm.</li>
</ul>

-> Example:

<pre><code class="language-javascript">{
  "alg": "HS256",
  "typ": "JWT"
}</code></pre>

<strong>Payload</strong> contains the claims. Claims are statements about an entity and additional information.
There are 3 types of claims ->
<ul>
<li><code>Registered claims</code> -> These are a set of predefined claims: <code>iss</code> (issuer), <code>exp</code> (expiration time), <code>sub</code> (subject)</li>
<li><code>Public claims</code></li>
<li><code>Private claims</code></li>
</ul>
Example ->

<pre><code class="language-javascript">{
  "id": 3,
  "iat": 1538339534,
  "exp": 1538425934
}</code></pre>

<strong>Signature</strong> -> 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 ->

<pre><code class="language-javascript">HMACSHA512(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  your-256-bit-secret
)</code></pre>

Combine all together, we get 3 Base64-URL strings separated by dots,

Example:

- Encoded ->

<pre>
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaWF0IjoxNTM4MzM5NTM0LCJleHAiOjE1Mzg0MjU5MzR9.wKse6-ERNP4g_sPBdM72GZgpNpHH87UGbzYH3_0mdpo
</pre>

- Decoded ->

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-decoded-token.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-decoded-token" width="531" height="508" class="alignnone size-full wp-image-15016" />

<h2 id="overview">Overview</h2>
<h3 id="demo">Demo</h3>
<iframe width="853" height="480" src="https://www.youtube.com/embed/3JZyMI3gh4c?rel=0" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
<h3 id="project-structure">Project Structure</h3>

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-project-structure.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-project-structure" width="174" height="423" class="alignnone size-full wp-image-15017" />

<ul>
<li><code>config</code> package defines MySQL Database Configuration, JWT Secret Key & User Roles.</li>
<li><code>model</code> package defines <code>Role</code> & <code>User</code> Sequelize models.

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-many-to-many-user-role.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-many-to-many-user-role" width="571" height="407" class="alignnone size-full wp-image-15018" />
</li>
<li><code>router</code> package defines RestAPI URLs, verification functions for signup, & verification JWT token function for signin.</li>
<li><code>controller</code> package defines proccesing functions for each RestAPIs declared in <code>router</code> package.</li>
</ul>
<h3 id="workflow">Workflow</h3>
We will define 5 workflows as below ->
<ul>
<li>SignUp Scenarios:

<pre><code class="language-javascript">
	-> Verify UserName & Email
	  -> If NOT Duplicate (UserName & Email), verify Roles are existed.
		-> If Roles are available, save User Info to database by Sequlieze ORM
	-> Othercase, Eror code will be returned</code></pre>
	
- Code in <code>router.js</code> ->

<pre><code class="language-javascript">
app.post('/api/auth/signup', [verifySignUp.checkDuplicateUserNameOrEmail, verifySignUp.checkRolesExisted], controller.signup);
</code></pre>
</li>

<li>SignIn Scenarios:

<pre><code class="language-javascript">
	-> Find User record in database by <code>username</code>
		-> If User is existed, check <code>password</code> is Valid or NOT
			-> If password is valid, create JWT then return JWT token back to client
	-> Othercase, Error code will be returned
</code></pre>
	
- Code in <code>router.js</code> ->
<pre><code class="language-javascript">
app.post('/api/auth/signin', controller.signin);
</code></pre>
</li>

<li> Access User Content:

<pre><code class="language-javascript">
	-> Verify JWT Token
		-> If token is valid, <code>controller</code> will load & return User Info back to client
	-> Othercase, Error Code will be returned
</code></pre>
	
- Code in <code>router.js</code> ->

<pre><code class="language-javascript">
app.get('/api/test/user', [authJwt.verifyToken], controller.userContent);
</code></pre>
</li>

<li> Access PM Content:

<pre><code class="language-javascript">
	-> Verify JWT Token
		-> If token is valid, verify <code>PM</code> role.
			-> If User has Admin or PM role, <code>controller</code> will load & return Management Content to client.
	-> Othercase, Error code will be returned
</code></pre>

- Code in <code>router.js</code> ->

<pre><code class="language-javascript">
app.get('/api/test/pm', [authJwt.verifyToken, authJwt.isPmOrAdmin], controller.managementBoard);
</code></pre>
</li>

<li> Access Admin Content

<pre><code class="language-javascript">
	-> Verify JWT Token
		-> If token is valid, verify <code>ADMIN</code> role.
			-> If User has Admin role, <code>controller</code> will load & return Admin Content to client.
	-> Othercase, Error code will be returned
</code></pre>

- Code in <code>router.js</code> ->

<pre><code class="language-javascript">
app.get('/api/test/admin', [authJwt.verifyToken, authJwt.isAdmin], controller.adminBoard);
</code></pre>
</li>
</ul>
<h3 id="goal">Goal</h3>
<strong>Sign Up</strong> ->

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-sign-up.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-sign-up" width="578" height="424" class="alignnone size-full wp-image-15019" />

<strong>Sign In</strong> ->

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-sign-in.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-sign-in" width="700" height="433" class="alignnone size-full wp-image-15022" />

<strong>Access API Successfully</strong> ->

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-access-user-role-api.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-access-user-role-api" width="708" height="526" class="alignnone size-full wp-image-15021" />

<strong>Unauthorized Access</strong> ->

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-can-NOT-access-PM-role-api.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-can-NOT-access-PM-role-api" width="709" height="293" class="alignnone size-full wp-image-15023" />
<h2 id="practice">Practice</h2>
<h3 id="create-nodejs-project">Create Nodejs Project</h3>
Following the <a href="https://grokonez.com/node-js/nodejs-restapis-how-to-create-nodejs-express-restapis-post-get-put-delete-requests#Setup_NodeJsExpress_project">guide</a> to create a NodeJS/Express project

Install Express, Sequelize, MySQL, Json Web Token, Bcryptjs:

<pre><code class="language-javascript">
$npm install express sequelize mysql2 jsonwebtoken bcryptjs --save
</code></pre>

-> <code>package.json</code> file:

<pre><code class="language-javascript">
{
  "name": "nodejs-jwt-auth",
  "version": "1.0.0",
  "description": "Nodejs-JWT-Authentication-with-MySQL-Sequelize-ORM",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "Nodejs",
    "Express",
    "JWT",
    "Sequelize",
    "MySQL",
    "Authentication"
  ],
  "author": "grokonez.com",
  "license": "ISC",
  "dependencies": {
    "bcryptjs": "^2.4.3",
    "express": "^4.16.3",
    "jsonwebtoken": "^8.3.0",
    "mysql2": "^1.6.1",
    "sequelize": "^4.39.0"
  }
}</code></pre>
<h3 id="create-sequelize-modules">Create Sequelize Models</h3>
- <code>User</code> model ->

<pre><code>
module.exports = (sequelize, Sequelize) =&gt; {
	const User = sequelize.define('users', {
	  name: {
		  type: Sequelize.STRING
	  },
	  username: {
		  type: Sequelize.STRING
	  },
	  email: {
		  type: Sequelize.STRING
	  },
	  password: {
		  type: Sequelize.STRING
	  }
	});
	
	return User;
}
</code></pre>

- <code>Role</code> model:

<pre><code class="language-javascript">module.exports = (sequelize, Sequelize) =&gt; {
	const Role = sequelize.define('roles', {
	  id: {
        type: Sequelize.INTEGER,
        primaryKey: true
	  },
	  name: {
		  type: Sequelize.STRING
	  }
	});
	
	return Role;
}</code></pre>
<h3>Sequelize Database Configuration</h3>
- <code>/app/config/env.js</code> file ->

<pre><code class="language-javascript">
const env = {
  database: 'testdb',
  username: 'root',
  password: '12345',
  host: 'localhost',
  dialect: 'mysql',
  pool: {
	  max: 5,
	  min: 0,
	  acquire: 30000,
	  idle: 10000
  }
};
 
module.exports = env;
</code></pre>

- <code>/app/config/db.config.js</code> ->

<pre><code class="language-javascript">
const env = require('./env.js');
 
const Sequelize = require('sequelize');
const sequelize = new Sequelize(env.database, env.username, env.password, {
  host: env.host,
  dialect: env.dialect,
  operatorsAliases: false,
 
  pool: {
    max: env.max,
    min: env.pool.min,
    acquire: env.pool.acquire,
    idle: env.pool.idle
  }
});
 
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;
</code></pre>

Because <code>Role</code> & <code>User</code> has <code>many-to-many</code> association, so we use <code>belongsToMany</code> to configure them.

-> See more at: <a href="https://grokonez.com/node-js/sequelize-many-to-many-association-nodejs-express-mysql">Sequelize Many-to-Many association – NodeJS/Express, MySQL</a>
<h3>Define RestAPIs Router</h3>
We define 5 RestAPIs in <code>/app/router/router.js</code>

<pre><code class="language-javascript">
const verifySignUp = require('./verifySignUp');
const authJwt = require('./verifyJwtToken');

module.exports = function(app) {

    const controller = require('../controller/controller.js');
 
	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);
}
</code></pre>

We need implement middleware functions to do a verification for <code>SignUp</code> & <code>SignIn</code>:

- <code>/app/router/verifySignUp.js</code> implements 2 middleware functions:
<ul>
<li><code>checkDuplicateUserNameOrEmail</code> -> checking the posted <code>username</code> or <code>email</code> is duplicated or NOT</li>
<li><code>checkRolesExisted</code> -> checking the posted User <code>Role</code> is existed or NOT</li>
</ul>

<pre><code class="language-javascript">
const db = require('../config/db.config.js');
const config = require('../config/config.js');
const ROLEs = config.ROLEs; 
const User = db.user;
const Role = db.role;

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;
</code></pre>

- <code>/app/router/verifyJwtToken.js</code> implements 3 middleware functions:

<ul>
<li><code>verifyToken</code> -> checking a JWT token is valid or NOT</li>
<li><code>isAdmin</code> -> checking an User has <code>ADMIN</code> role or NOT </li>
<li><code>isPmOrAdmin</code> -> checking an User has <code>PM</code> or <code>ADMIN</code> role or NOT</li>
</ul>

<pre><code class="language-javascript">const jwt = require('jsonwebtoken');
const config = require('../config/config.js');
const db = require('../config/db.config.js');
const Role = db.role;
const User = db.user;

verifyToken = (req, res, next) =&gt; {
	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) =&gt; {
		if (err){
			return res.status(500).send({ 
					auth: false, 
					message: 'Fail to Authentication. Error -&gt; ' + err 
				});
		}
		req.userId = decoded.id;
		next();
	});
}

isAdmin = (req, res, next) =&gt; {
	
	User.findById(req.userId)
		.then(user =&gt; {
			user.getRoles().then(roles =&gt; {
				for(let i=0; i&lt;roles.length; i++){
					console.log(roles[i].name);
					if(roles[i].name.toUpperCase() === &quot;ADMIN&quot;){
						next();
						return;
					}
				}
				
				res.status(403).send(&quot;Require Admin Role!&quot;);
				return;
			})
		})
}

isPmOrAdmin = (req, res, next) =&gt; {
	
	User.findById(req.userId)
		.then(user =&gt; {
			user.getRoles().then(roles =&gt; {
				for(let i=0; i&lt;roles.length; i++){					
					if(roles[i].name.toUpperCase() === &quot;PM&quot;){
						next();
						return;
					}
					
					if(roles[i].name.toUpperCase() === &quot;ADMIN&quot;){
						next();
						return;
					}
				}
				
				res.status(403).send(&quot;Require PM or Admin Roles!&quot;);
			})
		})
}

const authJwt = {};
authJwt.verifyToken = verifyToken;
authJwt.isAdmin = isAdmin;
authJwt.isPmOrAdmin = isPmOrAdmin;

module.exports = authJwt;</code></pre>
<h3>Implement Controller</h3>
- <code>/app/controller/controller.js</code> exports 5 funtions:
<ul>
<li><code>signup</code> -> be used to register new User</li>
<li><code>signin</code> -> be used to Login</li>
<li><code>userContent</code> -> get User Info</li>
<li><code>managementBoard</code> -> get Management Board Content</li>
<li><code>adminBoard</code> -> get Admin Board Content</li>
</ul>

<pre><code class="language-javascript">
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
	console.log("Processing func -> SignUp");
	
	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("User registered successfully!");
            });
		}).catch(err => {
			res.status(500).send("Error -> " + err);
		});
	}).catch(err => {
		res.status(500).send("Fail! Error -> " + err);
	})
}

exports.signin = (req, res) => {
	console.log("Sign-In");
	
	User.findOne({
		where: {
			username: req.body.username
		}
	}).then(user => {
		if (!user) {
			return res.status(404).send('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
		});
		
		res.status(200).send({ auth: true, accessToken: token });
		
	}).catch(err => {
		res.status(500).send('Error -> ' + err);
	});
}

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).json({
			"description": "User Content Page",
			"user": user
		});
	}).catch(err => {
		res.status(500).json({
			"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).json({
			"description": "Admin Board",
			"user": user
		});
	}).catch(err => {
		res.status(500).json({
			"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).json({
			"description": "Management Board",
			"user": user
		});
	}).catch(err => {
		res.status(500).json({
			"description": "Can not access Management Board",
			"error": err
		});
	})
}
</code></pre>

- Create <code>/app/config/config.js</code> file that defines <code>jwt-secret-key</code> & User Roles.

<pre><code class="language-javascript">
module.exports = {
  'secret': 'grokonez-super-secret-key',
  ROLEs: ['USER', 'ADMIN', 'PM']
};
</code></pre>
<h3>Server</h3>
- <code>/app/server.js</code> file ->

<pre><code class="language-javascript">
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();
});
 
//require('./app/route/project.route.js')(app);
 
// 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: "ADMIN"
	});
	
	Role.create({
		id: 3,
		name: "PM"
	});
}
</code></pre>
<h3>Run & Check Results</h3>
<h4>Start Nodejs Server</h4>
- Run Nodejs server by cmd <code>npm start</code> -> Logs:

<pre><code class="language-javascript">
npm start

> nodejs-jwt-auth@1.0.0 start D:\gkz\article\Nodejs-JWT-Authentication\nodejs-jwt-auth
> node server.js

App listening at http://:::8080
Executing (default): DROP TABLE IF EXISTS `user_roles`;
Executing (default): DROP TABLE IF EXISTS `roles`;
Executing (default): DROP TABLE IF EXISTS `users`;
Executing (default): DROP TABLE IF EXISTS `users`;
Executing (default): CREATE TABLE IF NOT EXISTS `users` (`id` INTEGER NOT NULL auto_increment , `name` VARCHAR(255), `username` VARCHAR(255), `email` VARCHAR(255), `password` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `users`
Executing (default): DROP TABLE IF EXISTS `roles`;
Executing (default): CREATE TABLE IF NOT EXISTS `roles` (`id` INTEGER , `name` VARCHAR(255), `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `roles`
Executing (default): DROP TABLE IF EXISTS `user_roles`;
Executing (default): CREATE TABLE IF NOT EXISTS `user_roles` (`createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, `roleId` INTEGER , `userId` INTEGER , PRIMARY KEY (`roleId`, `userId`), FOREIGN KEY (`roleId`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `user_roles`
Drop and Resync with { force: true }
Executing (default): INSERT INTO `roles` (`id`,`name`,`createdAt`,`updatedAt`) VALUES (1,'USER','2018-09-30 20:11:40','2018-09-30 20:11:40');
Executing (default): INSERT INTO `roles` (`id`,`name`,`createdAt`,`updatedAt`) VALUES (2,'ADMIN','2018-09-30 20:11:40','2018-09-30 20:11:40');
Executing (default): INSERT INTO `roles` (`id`,`name`,`createdAt`,`updatedAt`) VALUES (3,'PM','2018-09-30 20:11:40','2018-09-30 20:11:40');
</code></pre>

-> Check MySQL database:

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-table-schema.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-table-schema" width="412" height="628" class="alignnone size-full wp-image-15047" />

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-roles-tables.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-roles-tables" width="368" height="136" class="alignnone size-full wp-image-15048" />
<h4>Sign Up</h4>
<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-sign-up-1.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-sign-up" width="578" height="424" class="alignnone size-full wp-image-15024" />

-> All Logs of Sign Up:

<pre><code class="language-javascript">
Processing func -> SignUp
Executing (default): INSERT INTO `users` (`id`,`name`,`username`,`email`,`password`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'Adam','adamgkz','adam@grokonez.com','$2a$08$qJts8G2RD7/J6RJGIPKxRuAKJTI1.C0WK93cvPQY0xutx6DWXv.PW','2018-09-30 20:14:08','2018-09-30 20:14:08');
Executing (default): SELECT `id`, `name`, `createdAt`, `updatedAt` FROM `roles` AS `roles` WHERE (`roles`.`name` = 'user');
Executing (default): SELECT `createdAt`, `updatedAt`, `roleId`, `userId` FROM `user_roles` AS `user_roles` WHERE `user_roles`.`userId` = 1;
Executing (default): INSERT INTO `user_roles` (`createdAt`,`updatedAt`,`roleId`,`userId`) VALUES ('2018-09-30 20:14:08','2018-09-30 20:14:08',1,1);
Executing (default): SELECT `id`, `name`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'jackgkz' LIMIT 1;
Executing (default): SELECT `id`, `name`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`email` = 'jack@grokonez.com' LIMIT 1;
Processing func -> SignUp
Executing (default): INSERT INTO `users` (`id`,`name`,`username`,`email`,`password`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'Jack','jackgkz','jack@grokonez.com','$2a$08$vr8m87P4Lhz4AmewyZEo4uq7zFQWAfg5qPZZq9itzdPPcNjwIy7Gu','2018-09-30 20:15:41','2018-09-30 20:15:41');
Executing (default): SELECT `id`, `name`, `createdAt`, `updatedAt` FROM `roles` AS `roles` WHERE (`roles`.`name` = 'pm');
Executing (default): SELECT `createdAt`, `updatedAt`, `roleId`, `userId` FROM `user_roles` AS `user_roles` WHERE `user_roles`.`userId` = 2;
Executing (default): INSERT INTO `user_roles` (`createdAt`,`updatedAt`,`roleId`,`userId`) VALUES ('2018-09-30 20:15:41','2018-09-30 20:15:41',3,2);
Executing (default): SELECT `id`, `name`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`username` = 'thomasgkz' LIMIT 1;
Executing (default): SELECT `id`, `name`, `username`, `email`, `password`, `createdAt`, `updatedAt` FROM `users` AS `users` WHERE `users`.`email` = 'thomas@grokonez.com' LIMIT 1;
Processing func -> SignUp
Executing (default): INSERT INTO `users` (`id`,`name`,`username`,`email`,`password`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'Thomas','thomasgkz','thomas@grokonez.com','$2a$08$hMKkxpOfvSIrFlNtPZ4JkuBIlp27CCZyH/6qo7kRhoBetP113b29C','2018-09-30 20:16:11','2018-09-30 20:16:11');
Executing (default): SELECT `id`, `name`, `createdAt`, `updatedAt` FROM `roles` AS `roles` WHERE (`roles`.`name` = 'admin');
Executing (default): SELECT `createdAt`, `updatedAt`, `roleId`, `userId` FROM `user_roles` AS `user_roles` WHERE `user_roles`.`userId` = 3;
Executing (default): INSERT INTO `user_roles` (`createdAt`,`updatedAt`,`roleId`,`userId`) VALUES ('2018-09-30 20:16:11','2018-09-30 20:16:11',2,3);
</code></pre>

-> MySQL records:

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-after-signup-data.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-after-signup-data" width="671" height="394" class="alignnone size-full wp-image-15025" />
<h4>SignIn and Access Protected Resources</h4>
- <strong>Adam</strong> can access <code>api/test/user</code> url, can NOT access others.

-> Sign In:

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-sign-in-1.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-sign-in" width="700" height="433" class="alignnone size-full wp-image-15026" />

-> Access Protected Resources:

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-access-user-role-api-1.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-access-user-role-api" width="708" height="526" class="alignnone size-full wp-image-15027" />

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-can-NOT-access-PM-role-api-1.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-can-NOT-access-PM-role-api" width="709" height="293" class="alignnone size-full wp-image-15028" />

- <strong>Jack</strong> can access <code>api/test/user</code> & <code>api/test/pm</code> url.
Can NOT access <code>/api/test/admin</code> url.

-> Sign In:

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-jack-sign-in-1.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-jack-sign-in" width="749" height="429" class="alignnone size-full wp-image-15029" />

-> Access Protected Resources:

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-access-user-role-api.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-access-user-role-api" width="711" height="526" class="alignnone size-full wp-image-15030" />

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-access-PM-role-api.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-access-PM-role-api" width="716" height="524" class="alignnone size-full wp-image-15031" />

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-NOT-access-ADMIN-role-api.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-NOT-access-ADMIN-role-api" width="710" height="315" class="alignnone size-full wp-image-15032" />

– <strong>Thomas</strong> can access all URLs.

-> Sign In:

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-THOMAS-sign-in.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-THOMAS-sign-in" width="715" height="435" class="alignnone size-full wp-image-15033" />

-> Access Protected Resource:

<img src="https://grokonez.com/wp-content/uploads/2018/10/nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-THOMAS-can-access-ADMIN-role-api.png" alt="nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-THOMAS-can-access-ADMIN-role-api" width="715" height="526" class="alignnone size-full wp-image-15034" />
<h2>SourceCode</h2>
<a href="https://grokonez.com/wp-content/uploads/2018/10/Nodejs-JWT-Authentication.zip">Nodejs-JWT-Authentication</a>

https://ozenero.com/angular-spring-boot-jwt-authentication-example-angular-6-spring-security-mysql-full-stack-part-1-overview-and-architecture