Nodejs JWT Authentication - Nodejs/Express RestAPIs + JSON Web Token + BCryptjs + Sequelize + MySQL
nodejs
107
JWT
9
authentication
14
express
17
Male avatar

loveprogramming viết ngày 10/03/2021

https://grokonez.com/node-js/jwt/nodejs-jwt-authentication-nodejs-express-restapis-json-web-token-bcryptjs-sequelize-mysql

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:

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

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

Male avatar

loveprogramming

234 bài viết.
66 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Cùng một tác giả
Male avatar
1 0
Tutorial Link: (Link) (Ảnh) Django is a Pythonbased free and opensource web framework that follows the modeltemplateview architectural pattern. A...
loveprogramming viết 5 tháng trước
1 0
Male avatar
1 0
https://loizenai.com/angular11nodejspostgresqlcrudexample/ Angular 11 Node.js PostgreSQL Crud Example (Ảnh) Tutorial: “Angular 11 Node.js Postg...
loveprogramming viết 4 tháng trước
1 0
Male avatar
1 0
Angular Spring Boot jwt Authentication Example Github https://loizenai.com/angularspringbootjwt/ (Ảnh) Tutorial: ” Angular Spring Boot jwt Authe...
loveprogramming viết 4 tháng trước
1 0
Bài viết liên quan
White
5 2
__Chú thích__: Đây là bản dịch tiếng Việt của bài viết gốc của tôi. Nếu bạn muốn xem bản tiếng Anh, xin hãy trỏ tới URL (Link) Lời mở (Link) là ...
Lơi Rệ viết 6 năm trước
5 2
White
53 12
Tiếp nối series Authentication story của mình lần trước, chắc hẳn các bạn đã nắm rõ về bản chất của quá trình authentication, chính là Xác thực một...
Minh Monmen viết 2 năm trước
53 12
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


Male avatar
{{userFollowed ? 'Following' : 'Follow'}}
234 bài viết.
66 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!