Nodejs JWT Authentication – Nodejs/Express RestAPIs + JSON Web Token + BCryptjs + Sequelize + MySQL

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-feature-image-new

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:
Sequelize Many-to-Many association – NodeJS/Express, MySQL
Sequelize ORM – Build CRUD RestAPIs with NodeJs/Express, Sequelize, MySQL
– Fullstack with Angular: Angular & Nodejs JWT Authentication fullstack

Technologies

– Nodejs/Express
– Json Web Token
– BCryptjs
– Sequelize
– MySQL

JSON Web Token

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 JWT
  • Information 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 ->

{
  "id": 3,
  "iat": 1538339534,
  "exp": 1538425934
}

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:

– Encoded ->

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiaWF0IjoxNTM4MzM5NTM0LCJleHAiOjE1Mzg0MjU5MzR9.wKse6-ERNP4g_sPBdM72GZgpNpHH87UGbzYH3_0mdpo

– Decoded ->

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-decoded-token

Overview

Demo

Project Structure

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-project-structure

  • config package defines MySQL Database Configuration, JWT Secret Key & User Roles.
  • model package defines Role & User Sequelize models.

    nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-many-to-many-user-role

  • router package defines RestAPI URLs, verification functions for signup, & verification JWT token function for signin.
  • controller package defines proccesing functions for each RestAPIs declared in router package.
Workflow

We will define 5 workflows as below ->

  • SignUp Scenarios:
    	-> 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 in router.js ->

    app.post('/api/auth/signup', [verifySignUp.checkDuplicateUserNameOrEmail, verifySignUp.checkRolesExisted], controller.signup);
    
  • SignIn Scenarios:
    	-> Find User record in database by username
    		-> If User is existed, check password is Valid or NOT
    			-> If password is valid, create JWT then return JWT token back to client
    	-> Othercase, Error code will be returned
    

    – Code in router.js ->

    app.post('/api/auth/signin', controller.signin);
    
  • Access User Content:
    	-> Verify JWT Token
    		-> If token is valid, controller will load & return User Info back to client
    	-> Othercase, Error Code will be returned
    

    – Code in router.js ->

    app.get('/api/test/user', [authJwt.verifyToken], controller.userContent);
    
  • Access PM Content:
    	-> Verify JWT Token
    		-> If token is valid, verify PM role.
    			-> If User has Admin or PM role, controller will load & return Management Content to client.
    	-> Othercase, Error code will be returned
    

    – Code in router.js ->

    app.get('/api/test/pm', [authJwt.verifyToken, authJwt.isPmOrAdmin], controller.managementBoard);
    
  • Access Admin Content
    	-> Verify JWT Token
    		-> If token is valid, verify ADMIN role.
    			-> If User has Admin role, controller will load & return Admin Content to client.
    	-> Othercase, Error code will be returned
    

    – Code in router.js ->

    app.get('/api/test/admin', [authJwt.verifyToken, authJwt.isAdmin], controller.adminBoard);
    
Goal

Sign Up ->

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-sign-up

Sign In ->

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-sign-in

Access API Successfully ->

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-access-user-role-api

Unauthorized Access ->

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-can-NOT-access-PM-role-api

Practice

Create Nodejs Project

Following the guide to create a NodeJS/Express project

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

$npm install express sequelize mysql2 jsonwebtoken bcryptjs --save

-> package.json file:

{
  "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"
  }
}
Create Sequelize Models

User model ->

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

Role model:

module.exports = (sequelize, Sequelize) => {
	const Role = sequelize.define('roles', {
	  id: {
        type: Sequelize.INTEGER,
        primaryKey: true
	  },
	  name: {
		  type: Sequelize.STRING
	  }
	});
	
	return Role;
}
Sequelize Database Configuration

/app/config/env.js file ->

const env = {
  database: 'testdb',
  username: 'root',
  password: '12345',
  host: 'localhost',
  dialect: 'mysql',
  pool: {
	  max: 5,
	  min: 0,
	  acquire: 30000,
	  idle: 10000
  }
};
 
module.exports = env;

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

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;

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

-> See more at: Sequelize Many-to-Many association – NodeJS/Express, MySQL

Define RestAPIs Router

We define 5 RestAPIs in /app/router/router.js

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);
}

We need implement middleware functions to do a verification for SignUp & SignIn:

/app/router/verifySignUp.js implements 2 middleware functions:

  • checkDuplicateUserNameOrEmail -> checking the posted username or email is duplicated or NOT
  • checkRolesExisted -> checking the posted User Role is existed or NOT
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 Does NOT exist Role = " + req.body.roles[i]);
			return;
		}
	}
	next();
}

const signUpVerify = {};
signUpVerify.checkDuplicateUserNameOrEmail = checkDuplicateUserNameOrEmail;
signUpVerify.checkRolesExisted = checkRolesExisted;

module.exports = signUpVerify;

/app/router/verifyJwtToken.js implements 3 middleware functions:

  • verifyToken -> checking a JWT token is valid or NOT
  • isAdmin -> checking an User has ADMIN role or NOT
  • isPmOrAdmin -> checking an User has PM or ADMIN role or NOT
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) => {
	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 {
	
	User.findById(req.userId)
		.then(user => {
			user.getRoles().then(roles => {
				for(let i=0; i
Implement Controller

- /app/controller/controller.js exports 5 funtions:

  • signup -> be used to register new User
  • signin -> be used to Login
  • userContent -> get User Info
  • managementBoard -> get Management Board Content
  • adminBoard -> get Admin Board Content
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
		});
	})
}

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

module.exports = {
  'secret': 'grokonez-super-secret-key',
  ROLEs: ['USER', 'ADMIN', 'PM']
};
Server

- /app/server.js file ->

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"
	});
}
Run & Check Results
Start Nodejs Server

- Run Nodejs server by cmd npm start -> Logs:

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');

-> Check MySQL database:

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-table-schema

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-roles-tables

Sign Up

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-sign-up

-> All Logs of Sign Up:

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);

-> MySQL records:

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-after-signup-data

SignIn and Access Protected Resources

- Adam can access api/test/user url, can NOT access others.

-> Sign In:

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-sign-in

-> Access Protected Resources:

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-access-user-role-api

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-adam-can-NOT-access-PM-role-api

- Jack can access api/test/user & api/test/pm url.
Can NOT access /api/test/admin url.

-> Sign In:

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-jack-sign-in

-> Access Protected Resources:

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-access-user-role-api

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-access-PM-role-api

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-JACK-can-NOT-access-ADMIN-role-api

Thomas can access all URLs.

-> Sign In:

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-THOMAS-sign-in

-> Access Protected Resource:

nodejs-jwt-authentication-express-bcryptjs-jsonwebtoken-sequelize-THOMAS-can-access-ADMIN-role-api

SourceCode

Nodejs-JWT-Authentication



By grokonez | October 1, 2018.

Last updated on February 6, 2020.



Related Posts


23 thoughts on “Nodejs JWT Authentication – Nodejs/Express RestAPIs + JSON Web Token + BCryptjs + Sequelize + MySQL”

  1. Hello, i am getting an error on getRoles(), Unhandled rejection TypeError: Cannot read property ‘getRoles’ of null, if you can help me it will be great ! Really great tutorial on authentication.

    1. Hi friend, I has the same problem, I tried to fix It and I got It, the problem is because in the relationship (User Role) you should call with include Rol model in FindByPK (FindByID) with this your problem is fixed. this is the complete function:

      isPmOrAdmin = (req, res, next) => {
        
        User.findByPk(req.userId,{ include: [ Role ] })
          .then(user => {
            //console.log(user.roles[0].name);
              let roles = user.roles;
              for(let i=0; i<roles.length; i++){          
                //console.log("**--**",roles[i].name);
                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!");
          })
      }
      

      I hope that is not late to fix .

      King regards.

      Judlup

  2. Great Tutorial!
    Does this support database migration?
    If so, how can I add/edit/remove a field in a table without losing records?

    Thanks

  3. Hi,
    Many thanks for this tutorial, it helps me a lot for my project.
    It’s really well explained and illustrated !

    Thanks

  4. How about logout and update of password/change of password by user?

    You have done a good job, kindly finish the help for us.

  5. Hello, is there anyone can modify the same code which will be having only two roles say Admin and Volunteer and can access these as same as in the above code.

  6. Copied this exactly however when testing sign up I recieve this error and the App crashes:

    Unhandled rejection Error: WHERE parameter “username” has invalid “undefined” value

    1. when you’re sending data on postman select x-www-form-urlencoded instead of raw then add
      app.use(bodyParser.urlencoded({extended: true})); after app.use(bodyParser.json()); in server.js

  7. I am getting Error -> TypeError: user.setRoles is not a function in the controller.js signup function

  8. Great tutorial, Please upgrade the password encryption and decryption with the async methods of bcryptjs package.

Got Something To Say:

Your email address will not be published. Required fields are marked *

*