Skip to main content

Authentication: Register & Login using JWT in Express & MYSQL

In the previous tutorial, i showed how to upload form data with file using Multer & MYSQL in Express. This tutorial teaches you how to do authentication in Express using JWT (JSON Web Token) and MYSQL database. 

Why we need authentication? The requirement is to allow APIs access to only authorized users. 

A visitor creates a user account using username, email, and password. We are going to use bcrypt package to create an encrypted version of the password and to verify the password againts MYSQL database. Execute the following command to install bcrypt.

npm i bcrypt

Once the account is created successfully, he/she can login to the system. The login information is verified on Express server. If the log in information is correct, valid token will be created and returned to a client app. The client app that received the token need to pass the token to the server to get permission to access the APIs. The token has to be verified before granting permissions. The information in the token can be verified and trusted because it is digitally signed. 

In Express, we use jsonwebtoken package to create, sign, and verify a token. Run the command below to install jsonwebtoken.

npm i jsonwebtoken

To create and verify a token, jsonwebtoken needs a secret key. Generally, a secret key is stored .env file. Thus, in the root folder of the Express app, create .env file and add a secret key as shown below.

JWT_KEY="secretOrKeyJWTRandom"

In Express, to read the secret key, we used dotenv package. Let install it.

npm i dotenv

Now we are ready to create routes to handle user registration and login. in the routes folder, create user.routes.js file:

require('dotenv').config();
var router = require('express').Router();
const bcrypt = require('bcrypt');
const KEY = process.env.JWT_KEY;
const jwt = require('jsonwebtoken');
const db = require("../db/models");

// handle user registration
router.post('/createuser', async function(req, res) {

    if(req.body){
         // Get post data
        const { body } = req;
        const { username, email, password } = body;
        // created encrypted password
        let password_encrypted= await bcrypt.hash(password, 10);
        // add new user to database
        await db.User.create({
          username:username,
          email:email,
          password:password_encrypted,

        }).then(newuser =>{ // return success result
          return res.status(200).json({
            message: 'success',
            data: newuser,
          });
        }).catch(err => { // return err result
          res.status(500).send({
            message:
              err.message || "Some error occurred while inserting new user"
          });
        });
       
   
    }
});

// handle user log in
router.post('/auth', async function(req, res) {

   // Get post data
   const { username, password } = req.body;
   /* Any how email or password is blank */
   if (!username|| !password) {
     return res.json({
       message: 'Request missing username or password',
     });
   }
   // Check user in database
   await db.User.findOne({
     where: { username: username},
     attributes: ['id','username', 'email', 'password'],
     limit: 1,
   }).then(user =>{
      if(!user)  return res.json({
        message: 'Invalid user!',
      });
       /* Define variables */
      const dataUser = user.toJSON();
      const userId = dataUser.id,
      userEmail = dataUser.email,
      userPassword = dataUser.password;

      /* Check and compare password */
      bcrypt.compare(password, userPassword).then(isMatch => {
        if (isMatch) {
          // User matched
          // Create JWT Payload */
          const payload = {
            id: userId,
            email: userEmail,
          };
          // Sign token
         
          const token = jwt.sign(payload, KEY, {
                  expiresIn: '72h'
          });
          res.json({ message: 'success', token:token });

        } else {
          res.json({ message: 'Password incorrect' });
        }
      });
 
   });
   
});

module.exports = router;
   

Then add the user.routes.js file to app.js.

....................
app.use('/api', require('./routes/user.routes'));
app.use('/api', require('./routes/product.routes'));
......................

Save the project and run node app.js to start Express server. Try create a new user using http://localhost:5000/api/crreateuser url. Then login to obtain a token using http://localhost:5000/api/auth url.

Protect APIs

To protect APIs or routes, you need a middleware to verify the submitted token. If the verification is successful, next handler method will be executed. Otherwise "unauthorized" error message will be returned to the client. 
In the root folder of the project, create utils folder and add verifyToken.js file to the folder.

utils/verifyToken.js
require('dotenv').config();
const jwt = require('jsonwebtoken');
const KEY = process.env.JWT_KEY;

const verifyToken = function(req, res, next) {

const bearerHeader = req.headers['authorization'];
  if (!bearerHeader) {
    res.status(401).send('Unauthorized: No token provided');
  } else {
    let token = bearerHeader.split(' ')[1];

    jwt.verify(token, KEY, function(err, decoded) {
      if (err) {
       
        res.status(401).send('Unauthorized: Invalid token');
      } else {
        req.email = decoded.username;
        next();
      }
    });
  }
}
module.exports = verifyToken;

To protect an API, you need to add the verifyToken middleware function to the handler method of the route. For example, to project routes to list products, add, and update product, update the product.routes.js file to include verifyToken middleware:

...................   
const verifyToken = require('../utils/verifyToken');

router.get("/products", verifyToken, function(req,res){.....}
router.post("/products", verifyToken, function(req,res){......}
router.put("/products", verifyToken, function(req,res){.....}

Comments

Popular posts from this blog

Get start with React

To start web development with React, i recommend you install Node. Node comes with NPM (package manager) helps you easy to add dependencies, create, start, and build your React apps. You can download and install NPM from its official web site: Download NPM . Another useful tool for coder is Visual Studio Code . On my Windows machine, i have installed Node version 16.10.0 with NPM 7.14.0. Now create a project folder and name it react_tutorials in Drive D: or other drive of your choice. Then open the folder in Visual Studio COde (VSC). From the VSC editor, select Terminal. In the terminal, enter the following command to create my-app app in the project folder created above. D:\react_tutorials>npm init react-app my-app After the my-app app is created successfully. You change to my-app folder (cd my-app) . Then You run " npm start " command to start your first react app on browser. React automatically starts on port 3000.

Why React?

React is one of the top UI development frameworks. It is very popular today among web developers around the globe. I love React because of the following things: - It is simple to learn and use. - It is JavaScript library. - It effectively applies changes to a web page without reloading the page while data changed. - It is easy to find problems or errors while you are coding.

React Express & Mysql: Sequelize

Now, you have React project in my-app folder and Express project in prod_project folder. We are going to create back-end APIs that will be accessed by our React app. If you don't have React and Express apps set up, you go to the page Product CRUD Project In the prod_project folder, run the following command to install dependencies that are required to create the APIs on Express server. D:\prod_project> npm install sequelize sequelize-cli mysql2 jsonwebtoken cors body-parser bcrypt sequelize helps us synchronize the models (defined later in our project) with Mysql database. From the models, you can create tables in the database, query, add, update, delete data in the tables. sequelize-cli - Sequelize Command Line Interface helps us create models, migrations, and database. mysql2   is a fast mysql driver to work with mysql database from Express. jsonwebtoken works in user authentication by token for securely transmitting data between our back-end Express and front-end...