Complete JWT Authentication and Authorization System for MySQL/Node.js API

Authentication and authorization are the essential features in every API because they are related directly to the security of your application while exchanging information.  JWT(JSON Web Token) is a popular standard used to share security information and trust requests between two parties: a client and a server.

This article will implement a complete authentication and authorization system with JWT to add a security layer to access protected routes within our MySQL/Node.js API.

Related Articles:

1- The JWT Token standard structure (format)

JWT (JSON Web Token) is an open standard used to share security information between a client and a server. The JSON Web Token (JWT) is stored on the Client side: Local Storage for Browser, Keychain for IOS, and SharedPreferences for Android.

A JWT contains an encoded JSON object created by the server from the user login data to represent the user identity. The client saves the JWT token and attaches it to every request to allow the server to verify and validate the identity then return the response.

JSON Web Tokens consist of three parts separated by dots (.): Header, Payload, and Signature

The standard structure looks like the following:

Header.Payload.Signature.

In the header, we find two pieces of information: the type of the token, which is JWT, and the signing algorithm used to generate the token signature( HS256, HMAC SHA256, or RSA).

{
  "alg": "HMAC SHA256",
  "typ": "JWT"
}

Payload

The Payload contains the claims (the user data). Claims can be registeredpublic, and private.

  • Registered claims: These claims are predefined and optional but recommended to provide a set of valuable, interoperable claims, such as iss (issuer), exp (expiration time), sub (subject), aud (audience).
  • Public claims: These can be defined at will by those using JWTs. But to avoid collisions, they should be defined in the IANA JSON Web Token Registry or be defined as a URI that contains a collision-resistant namespace.
  • Private claims: These are the custom claims created to share information between parties who agree to use them and are neither registered nor public claims.

An example of payload:

{
  "id": "1234577890",
  "name": "Jo",
  "email": "[email protected]",
  "admin": false
}

Signature

The signature is used to verify the message wasn’t changed along the way. So to create the signature, we need first to Base64Url encode the header and the Payload, then combine the two encoded parts with a secret using the algorithm specified previously in the header, and sign that like following:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

2- MySQL/Node.js boilerplate API for a JWT authentication and Authorization

We will start our tutorial with a boilerplate MySQL/Node.js API named “jwt-example”. The project directory contains the following files:

  • server.js: Our boilerplate for the node.js server uses express as a web server. We mount the existing apiRouter into server.js.
  • .env: To save all your environment variables and the configuration data and database connection options for the MySQL database.
  • db.js: In this file, we will write our queries to connect the database and interact with its tables. We define these queries as methods of the db object in db.js.
  • apiRouter.js: This apiRouter file will be the starting point for all your API routes.
  • user.js: in this file, we will write all the user CRUD routes with restricted access; only users with a role admin can access these routes.

If you want to know more details about the start-server we are using in this article, go ahead and check this article: Complete Guide to Build a RESTful API with Node.js and Express

server.js

 require("dotenv").config();
const express =require('express');
const bodyParser = require('body-parser');
const cors = require('cors');

const apiRouter = require('./apiRouter');
   
const app = express();
   
   
   
const PORT= process.env.PORT;
   
app.use(bodyParser.json());
app.use(cors());

   
app.use('/apiRouter',apiRouter)
   
app.listen(PORT, ()=>{
    console.log(`server is listening  on ${PORT}`);
});
   
module.exports = app;

.env

 
  PORT = 3000
DB_PORT = “yourDBport”
DB_HOST = localhost
DB_USER = “yourusername”
DB_PASS = “yourDBpassword”
MYSQL_DB = “yourDBname”
CONNECTION_LIMIT = 10

package.json

//package.json
   
{
  "name": "jwt-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "nodemon server.js "
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "dotenv": "^8.2.0",
    "express": "^4.17.1",
     "mysql": "^2.18.1",
    "nodemon": "^2.0.4",
    "save": "^2.4.0"
  }
}

  

apiRouter.js

 //apiRouter.js
   
const express =require('express');
const apiRouter = express.Router();
   
   
module.exports = apiRouter;

In this tutorial, we will store our data in a MySQL database named “jwtDB” with one table named “User

We will use the following queries to create the User table:

 
   //create the User table
  
    pool.query('CREATE TABLE User (' +
          'id int(11) NOT NULL AUTO_INCREMENT,' +
          'user_name varchar(255) NOT NULL,' +
          'role varchar(255) default "employee",' +
          'email varchar(255) NOT NULL,' +
          'password varchar(255) NOT NULL,' +
          'PRIMARY KEY (id),'+
          'UNIQUE KEY email_UNIQUE (email),' +
          'UNIQUE KEY password_UNIQUE (password))', function (err, result) {
              if (err) throw err;
              console.log("User created");
            }
         );

If you want to know how to create a database using node.js, click here: How to create MySQL database using node.js.

We use connection pooling instead of a single connection to connect our database. If you want to know more about connection pooling, read this article: Why is Connection Pooling better than Single Connection?.

db.js

  //db.js
   
const mysql = require('mysql');
  
   
   
const pool = mysql.createPool({
    connectionLimit: process.env.CONNECTION_LIMIT,    // the number of connections node.js will hold open to our database
    password: process.env.DB_PASS,
    user: process.env.DB_USER,
    database: process.env.MYSQL_DB,
    host: process.env.DB_HOST,
    port: process.env.DB_PORT
   
});
   

    //create the User table
  
    pool.query('CREATE TABLE User (' +
          'id int(11) NOT NULL AUTO_INCREMENT,' +
          'user_name varchar(255) NOT NULL,' +
          'role varchar(255) default "employee",' +
          'email varchar(255) NOT NULL,' +
          'password varchar(255) NOT NULL,' +
          'PRIMARY KEY (id),'+
          'UNIQUE KEY email_UNIQUE (email),' +
          'UNIQUE KEY password_UNIQUE (password))', function (err, result) {
              if (err) throw err;
              console.log("User created");
            }
         );
   
  
   
let db = {}; //create an empty object you will use later to write  and export your queries. 
   
module.exports = db

3- Authentication using the JWT Token

Authentication is the process of verifying a user’s identification through the acquisition of credentials and using those credentials to confirm the user’s identity. When the user successfully registers or logs in, the server will return a JSON Web Token. This token will be saved on the client-side for a predefined period. To prevent security issues, we should not keep tokens longer than required.

3.1- Where and How to store the JWT token

There are three options available to store JWT tokens on the client side:

  • LocalStorage.
  • Session Storage.
  • Cookie

We will store our JWT token in an httpOnly cookie for security and safety reasons. Using the httpOnly flag means that the cookie can’t be read using JavaScript but can still be sent back automatically to the server in every HTTP request. We use the httpOnly option to prevent XSS attacks.

In addition to that, we need to make sure that the cookie expires when the JWT expires, so we use the expires option. We also use the secure=true option, so the request and the cookie can only be sent over HTTPS.

In addition to the previous options, we will use the SameSite=strict flag. This flag is usually used to prevent CSRF because this option will not allow the cookie (JWT token) to be passed through cross-domain requests, and a simple link redirect will make your user log out from your application. Notice that this option can only be used if the authorization server has the same site as your front end, and that is the case in our example.

If it is not the case for your application and your frond-end app and your API are running on different ports, your authorization server must set CORS headers in the back-end.

Let’s say that your front-end app is running on port 3001 and the API on 3000. To send the JWT token in a cookie, you need to run the two apps(front-end and back-end) on the same port because cookies can only go to the origins from which they came. To do that, you add the CORS middleware in your server.js as follows:

 app.use(cors({
    origin: 'http://localhost:3001',
    credentials: true
}));

Now it s time to add routes that will generate the JWT token.

3.2- Create Routes to Generate the JWT Token

We can generate a token in two cases: register and login into our application.

But before we start coding, we need to install and import the following node.js packages into your server.js file :

  • jsonwebtoken : This is a JWT implementation for node.js.
  • bcrypt: A library to help us hash passwords.
  • cookie-parser: an express middleware that allows parsing cookies and populating the req.cookies with an object.
 npm install --save jsonwebtoken bcrypt cookie-parser

server.js

 require("dotenv").config();
const express =require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const cookieParser = require('cookie-parser');

const apiRouter = require('./apiRouter');
   
const app = express();
   
   
   
const PORT= process.env.PORT;
   
app.use(bodyParser.json());
app.use(cors());

apiRouter.use(cookieParser());

app.use('/apiRouter',apiRouter)
   
app.listen(PORT, ()=>{
    console.log(`server is listening  on ${PORT}`);
});
   
module.exports = app;

  

The next step is to write the queries to manage the User table in our database. We define these queries as methods of the db object in db.js.

db.js

   //db.js
   
  const mysql = require('mysql');
  
   
   
  const pool = mysql.createPool({
      connectionLimit: process.env.CONNECTION_LIMIT,    // the number of connections node.js will hold open to our database
      password: process.env.DB_PASS,
      user: process.env.DB_USER,
      database: process.env.MYSQL_DB,
      host: process.env.DB_HOST,
      port: process.env.DB_PORT
     
  });
     
  
    //  //create the User table
  
    // pool.query('CREATE TABLE User (' +
    //       'id int(11) NOT NULL AUTO_INCREMENT,' +
    //       'user_name varchar(255) NOT NULL,' +
    //       'role varchar(255) default "employee",' +
    //       'email varchar(255) NOT NULL,' +
    //       'password varchar(255) NOT NULL,' +
    //       'PRIMARY KEY (id),'+
    //       'UNIQUE KEY email_UNIQUE (email),' +
    //       'UNIQUE KEY password_UNIQUE (password))', function (err, result) {
    //           if (err) throw err;
    //           console.log("User created");
    //         }
    //      );
     
    
     
  let db = {};
  
  // ***Requests to the User table ***
  
  db.allUser = () =>{
      return new Promise((resolve, reject)=>{
          pool.query('SELECT * FROM User ', (error, users)=>{
              if(error){
                  return reject(error);
              }
              return resolve(users);
          });
      });
  };
  
  
  db.getUserByEmail = (email) =>{
      return new Promise((resolve, reject)=>{
          pool.query('SELECT * FROM User WHERE email = ?', [email], (error, users)=>{
              if(error){
                  return reject(error);
              }
              return resolve(users[0]);
          });
      });
  };
  
  
  
  db.insertUser = (userName, email, password) =>{
      return new Promise((resolve, reject)=>{
          pool.query('INSERT INTO User (user_name, email, password) VALUES (?,  ?, ?)', [userName, email, password], (error, result)=>{
              if(error){
                  return reject(error);
              }
              
                return resolve(result.insertId);
          });
      });
  };
  
  
  db.updateUser = (userName, role, email, password, id) =>{
      return new Promise((resolve, reject)=>{
          pool.query('UPDATE User SET user_name = ?, role= ?, email= ?, password=? WHERE id = ?', [userName, role, email, password, id], (error)=>{
              if(error){
                  return reject(error);
              }
              
                return resolve();
          });
      });
  };
  
  
  
  db.deleteUser = (id) =>{
      return new Promise((resolve, reject)=>{
          pool.query('DELETE FROM User WHERE id = ?', [id], (error)=>{
              if(error){
                  return reject(error);
              }
              return resolve(console.log("User deleted"));
          });
      });
  };
  
  
  
     
  module.exports = db
  

3.3- Register Route

Here we expect the user to enter three values, a user name, an email, and a password. The default value of role or position will be set to ’employee’, and only a user with role admin can change it. We must hash and verify passwords for security reasons before saving them in the database. We use the bcrypt module to generate a password hash, store it in the database, and later verify it during the login process.

Once the user is created, we generate a JW Token using the sign() .

 
 apiRouter.post('/register', async (req, res, next)=>{
     try{
         const userName = req.body.userName;
         const email = req.body.email;
         let password = req.body.password;
  
  
               if (!userName || !email || !password) {
                 return res.sendStatus(400);
              }
  
              const salt = genSaltSync(10);
              password = hashSync(password, salt);
  
               
  
         const user =  await db.insertUser(userName, email, password);
         
         const jsontoken = jsonwebtoken.sign({user: user}, process.env.SECRET_KEY, { expiresIn: '30m'} );
         res.cookie('token', jsontoken, { httpOnly: true, secure: true, SameSite: 'strict' , expires: new Date(Number(new Date()) + 30*60*1000) }); //we add secure: true, when using https.
 
 
         res.json({token: jsontoken});
 
             //return res.redirect('/mainpage');
  
     } catch(e){    
         console.log(e);
         res.sendStatus(400);
     }
 });
 

 

3.4- Login Route

In this section, we will create a route for the user login by defining a POST method. To create and get the JSON Web Token, we use the sign() method. This method takes the user data, a secret key, and the token expiration time as parameters.

 
  apiRouter.post('/login', async(req, res, next)=>{
     try{
     const email = req.body.email;
     const password = req.body.password;
     user = await db.getUserByEmail(email);
     
     if(!user){
         return res.json({
             message: "Invalid email or password"
         })
     }
 
     const isValidPassword = compareSync(password, user.password);
     if(isValidPassword){
         user.password = undefined;
         const jsontoken = jsonwebtoken.sign({user: user}, process.env.SECRET_KEY, { expiresIn: '30m'} );
         res.cookie('token', jsontoken, { httpOnly: true, secure: true, SameSite: 'strict' , expires: new Date(Number(new Date()) + 30*60*1000) }); //we add secure: true, when using https.
 
         res.json({token: jsontoken});
        //return res.redirect('/mainpage') ;
 
     }  else{
         return res.json({
             message: "Invalid email or password"
         });
     } 

     } catch(e){
         console.log(e);
     }
 });

Notice that we save our secret key in the .env file with the other environment variables to keep it safe. This key can be any random string, but make sure that nobody else can generate the same secret key and gain access to your API.

.env

  PORT = 3000
DB_PORT = “yourDBport”
DB_HOST = localhost
DB_USER = “yourusername”
DB_PASS = “yourDBpassword”
MYSQL_DB = jwtDB
CONNECTION_LIMIT = 10

SECRET_KEY = 'secret_key'

apiRouter.js

 
  //apiRouter.js


 const express =require('express');
 const apiRouter = express.Router();
 
  const jsonwebtoken = require('jsonwebtoken');
 const db = require('./db');
 const { hashSync, genSaltSync, compareSync } = require("bcrypt");
 const cookieParser = require('cookie-parser');
 
 


 apiRouter.use(cookieParser());
 
 apiRouter.post('/register', async (req, res, next)=>{
     try{
         const userName = req.body.userName;
         const email = req.body.email;
         let password = req.body.password;
  
  
               if (!userName || !email || !password) {
                 return res.sendStatus(400);
              }
  
              const salt = genSaltSync(10);
              password = hashSync(password, salt);
  
               
  
         const user =  await db.insertUser(userName, email, password);
         
         const jsontoken = jsonwebtoken.sign({user: user}, process.env.SECRET_KEY, { expiresIn: '30m'} );
         res.cookie('token', jsontoken, { httpOnly: true, secure: true, SameSite: 'strict' , expires: new Date(Number(new Date()) + 30*60*1000) }); //we add secure: true, when using https.
 
 
         res.json({token: jsontoken});
 
             //return res.redirect('/mainpage');
  
     } catch(e){    
         console.log(e);
         res.sendStatus(400);
     }
 });
 
 
 
 
  apiRouter.post('/login', async(req, res, next)=>{
     try{
     const email = req.body.email;
     const password = req.body.password;
     user = await db.getUserByEmail(email);
     
     if(!user){
         return res.json({
             message: "Invalid email or password"
         })
     }
 
     const isValidPassword = compareSync(password, user.password);
     if(isValidPassword){
         user.password = undefined;
         const jsontoken = jsonwebtoken.sign({user: user}, process.env.SECRET_KEY, { expiresIn: '30m'} );
         res.cookie('token', jsontoken, { httpOnly: true, secure: true, SameSite: 'strict' , expires: new Date(Number(new Date()) + 30*60*1000) }); //we add secure: true, when using https.
 
         res.json({token: jsontoken});
        //return res.redirect('/mainpage') ;
 
     }  else{
         return res.json({
             message: "Invalid email or password"
         });
     } 

     } catch(e){
         console.log(e);
     }
 });
 
 
 
 

   
   
module.exports = apiRouter;

4- Authorization using the JWT Token

The authorization process always follows the authentication procedure to allow authenticated users to access protected routes, services, and resources by determining whether they have system access permissions.

An Authorization system using JWT means once the user is successfully logged in, the server creates a signed token and sends it back to the client. Then this JWT token will be included in each one of the client requests. Once the request is received, the API will verify that the JWT’s signature matches to determine that the JWT is valid and wasn’t altered by a third party, allowing the user to access the protected routes. 

4.1- Create the protected routes for User management

To add and implement our authorization layer, we need to create the routes we want to protect. The protected routes are all CRUD routes dedicated to the User table management in our API. Will write these routes in the user.js file.

user.js

 
  const express =require('express');
  const db = require('./db');
  const userRouter = express.Router();
  
  const { hashSync, genSaltSync, compareSync } = require("bcrypt");
  
  
  
  
  userRouter.param('userId', async (req, res, next, userId)=> {
      try{
          const user = await db.getOne("User", userId);
          req.user = user;
          next();
      } catch(e) {
          console.log(e);
          res.sendStatus(404);
      }
  });
  
  
  
  userRouter.get('/:userId',  (req, res, next)=>{
      res.status(200).json({user: req.user});
  
  });
  
  
  
  
  userRouter.post('/',  async (req, res, next)=>{
      try{
          const userName = req.body.user.userName;
          const email = req.body.user.email;
          let password = req.body.user.password;
  
  
                if (!userName || !email || !password) {
                  return res.sendStatus(400);
               }
  
               const salt = genSaltSync(10);
               password = hashSync(password, salt);
  
               
  
          const user =  await db.insertUser(userName, email, password);
          res.json({user: user});
             
  
      } catch(e){    
          console.log(e);
          res.sendStatus(400);
      }
  });
  
  
  
  
  userRouter.put('/:id',  async (req, res, next)=>{
      try{
          const userName = req.body.user.userName;
          const role = req.body.user.role;
          const email = req.body.user.email;
          let password = req.body.user.password;
          const userId = req.params.id;
  
  
                if (!userName || !role || !email || !password) {
                  return res.sendStatus(400);
               }
  
               const salt = genSaltSync(10);
               password = hashSync(password, salt);
  
               
  
          const user =  await db.updateUser(userName, role, email, password, userId);
          res.json({message: "user updated" });
             
  
      } catch(e){    
          console.log(e);
          res.sendStatus(400);
      }
  });
  
  
  
  userRouter.delete('/:id',  async (req, res, next)=>{
      try{
          const userId = req.params.id
          const user =  await db.deleteUser(userId);
          return res.sendStatus(204);
      
      } catch(e){    
          console.log(e);
          res.sendStatus(400);
      }
  });
  
  
  
  userRouter.get('/', async (req, res, next)=>{
      try {
          const users = await db.allUser();
          res.json({users: users});
      } catch(e) {
          console.log(e);
      }
  });
  
  
  
  
  
  
  
  
  module.exports = userRouter;

4.2- Create Node JWT “verifyToken” middleware

The verifyToken middleware is the authorization middleware of our API. We will add this middleware function to the user router inside the apiRouter.js file to verify if the token is valid before allowing access.

To create the middleware to verify the token included in a request, we need to follow these steps:

Step 1: Get the token value from the cookie coming with the request.

Step 2: Check if the token is undefined.

Step 3: Verify if the token is valid using the verify().

Step 4: get the user role from the Authentication data.

Step 5: If the user is an admin, he can go to next and access user management routes. Otherwise, he will get an error message.

 
  //  Verify Token
 async function  verifyToken  (req, res, next){
    
    const token=req.cookies.token;
     console.log(token);
     
     if(token === undefined  ){
         
             return res.json({
                 message: "Access Denied! Unauthorized User"
               });
     } else{
 
         jsonwebtoken.verify(token, process.env.SECRET_KEY, (err, authData)=>{
             if(err){
                 res.json({
                     message: "Invalid Token..."
                   });
 
             } else{
                
                
                const role = authData.user.role;
                if(role === "admin"){

                 next();
                } else{
                    return res.json({
                        message: "Access Denied! you are not an Admin"
                      });

                }
             }
         })
     } 
 }
 


4.3- Add Verification middleware (verifyToken function) to the User route

Now inside the apiRouter.js, we mount the userRouter and create the new protected route ‘/user’ using the verifyToken function.

apiRouter.js

  //apiRouter.js


 const express =require('express');
 const apiRouter = express.Router();
 
  const jsonwebtoken = require('jsonwebtoken');
 const db = require('./db');
 const { hashSync, genSaltSync, compareSync } = require("bcrypt");
 const cookieParser = require('cookie-parser');
 
 const userRouter = require('./user');


 apiRouter.use(cookieParser());
 
 apiRouter.post('/register', async (req, res, next)=>{
     try{
         const userName = req.body.userName;
         const email = req.body.email;
         let password = req.body.password;
  
  
               if (!userName || !email || !password) {
                 return res.sendStatus(400);
              }
  
              const salt = genSaltSync(10);
              password = hashSync(password, salt);
  
               
  
         const user =  await db.insertUser(userName, email, password);
         
         const jsontoken = jsonwebtoken.sign({user: user}, process.env.SECRET_KEY, { expiresIn: '30m'} );
         res.cookie('token', jsontoken, { httpOnly: true, secure: true, SameSite: 'strict' , expires: new Date(Number(new Date()) + 30*60*1000) }); //we add secure: true, when using https.
 
 
         res.json({token: jsontoken});
 
             //return res.redirect('/mainpage');
  
     } catch(e){    
         console.log(e);
         res.sendStatus(400);
     }
 });
 
 
 
 
  apiRouter.post('/login', async(req, res, next)=>{
     try{
     const email = req.body.email;
     const password = req.body.password;
     user = await db.getUserByEmail(email);
     
     if(!user){
         return res.json({
             message: "Invalid email or password"
         })
     }
 
     const isValidPassword = compareSync(password, user.password);
     if(isValidPassword){
         user.password = undefined;
         const jsontoken = jsonwebtoken.sign({user: user}, process.env.SECRET_KEY, { expiresIn: '30m'} );
         res.cookie('token', jsontoken, { httpOnly: true, secure: true, SameSite: 'strict' , expires: new Date(Number(new Date()) + 30*60*1000) }); //we add secure: true, when using https.
 
         res.json({token: jsontoken});
        //return res.redirect('/mainpage') ;
 
     }  else{
         return res.json({
             message: "Invalid email or password"
         });
     } 

     } catch(e){
         console.log(e);
     }
 });
 
 
 
 
 
 
 
 
    
  
 //  Verify Token
 async function  verifyToken  (req, res, next){
    
    const token=req.cookies.token;
     console.log(token);
     
     if(token === undefined  ){
         
             return res.json({
                 message: "Access Denied! Unauthorized User"
               });
     } else{
 
         jsonwebtoken.verify(token, process.env.SECRET_KEY, (err, authData)=>{
             if(err){
                 res.json({
                     message: "Invalid Token..."
                   });
 
             } else{
                
                console.log(authData.user.role);
                const role = authData.user.role;
                if(role === "admin"){

                 next();
                } else{
                    return res.json({
                        message: "Access Denied! you are not an Admin"
                      });

                }
             }
         })
     } 
 }
 
 
 
 
 
    apiRouter.use('/user', verifyToken, userRouter);
 
 
    
 module.exports = apiRouter;
 

5- Testing our authentication and authorization API with Postman

5.1- Register a user

To register a user using our API, you need to use the following setting in your Postman:

  • Path: apiRouter/register
  • Method: POST
  • URL: http://localhost:3000/apiRouter/register
  • Change the body type to “raw”
  • Change the format to “JSON”
  • The json object:

{ “userName”: “sam”, “email”: “[email protected]”, “password”: “123sam”}

  • click send and you will get a token in the response body.

You can check your database using Workbench, and here you can change the role of our first user to admin manually so we can continue our demonstration in the following sections.

5.2- Login a user:

To login to our API, you need to use the following setting in your Postman:

  • Path: apiRouter/login
  • Method: POST
  • URL: http://localhost:3000/apiRouter/login
  • Change the body type to “raw”
  • Change the format to “JSON”
  • The json object:

{ “email”: “[email protected]”, “password”: “123sam”}

  • click send and you will get a token in the response body.

5.3- Access the user protected routes

The protected routes in our API are the user routes. The user needs to be an admin and send a valid token with all your requests to access these routes. The following section will show you how to send the token you got after login in with a new postman request.

5.3.1- How to add JWT token in the Postman Manage Cookies ?

Once you get your token in the response body after registering or logging in, you copy the token’s value. Then under the send button, you click on Cookies.

Inside the manage cookies windows:

  1. first, add the domain name: in our case is localhost.
  2. Next, create a new cookie named token and has the token from the login response as a value.
  3. Then save the cookie.

This will allow us to save the token in cookies and send it with our requests.

5.3.2- Update a user with an admin account

Update a user is a protected route, so to access this route, the user needs to log in as admin, add the token in the manage cookies as mentioned in the previous section then use the following setting in your Postman:

  • Path: apiRouter/user/11
  • Method: PUT
  • URL: http://localhost:3000/apiRouter/user/11
  • Change the body type to “raw”
  • Change the format to “JSON”
  • The json object:

{ “user”:{ “userName”: “user11”, “role”: “employee”, “email”: “[email protected]”, “password”: “123user11” }}

  • click send and you will get a token in the response body.

5.3.3- Delete user with an employee account

To check if our DELETE route is protected, we need first to log in as an employee then try to access the delete user route :

Now you can open a new request and use the following setting:

  • Path: apiRouter/user/13
  • Method: PUT
  • URL: http://localhost:3000/apiRouter/user/13
  • Change the body type to “raw”
  • Change the format to “JSON”

As you can see, the employee user doesn’t have access to the user delete route, which is the case for all the other user management routes in our API. You can go ahead check that by yourself.

6- Conclusion

In this JWT authentication and authorization tutorial, we learned how to use JWT to add a security layer within a MySQL/Node.js web application. We started by discussing the basics of JWT then we showed you how to store JWT token in cookies to prevent security issues. Finally, we gave you a practical example covering its implementation in a MySQL/Node.js application.

You might also like:

Node.js + MySQL : Add Forgot/Reset Password to Login-Authentication System.

How to Build a Complete API for User Login and Authentication using MySQL and Node.js.

How to store Session in MySQL Database using express-mysql-session.

How to interact with MySQL database using async/await promises in node.js ?

How to use Sequelize async/await to interact with MySQL database in Node.js.

MANY-TO-MANY Association in MYSQL Database using Sequelize async/await with Node.js.

ONE-TO-ONE Association in MYSQL Database using Sequelize async/await with Node.js

ONE-TO-ONE Association in MYSQL Database using Sequelize async/await with Node.js.

How to add Routes to insert data into MySQL database-related tables in Node.js API?

Example How to use initialize() Function in Node.js/Express API .

Why is Connection Pooling better than Single Connection?.

How to create MySQL database using node.js.

2 thoughts on “Complete JWT Authentication and Authorization System for MySQL/Node.js API”

Leave a Comment

Your email address will not be published.

Translate »