Web App Setup
4. Middleware

Intro

In case of need, check out to the branch called 4_middleware. This branch has already implemented authentication using jwt tokens and also encryption and decryption of the passwords using bcrypt.

Next steps

  • Current implementation is that when the user is authenticated, the client will have access to the jwt token. Now, every time the client is requesting the server to gain access to the private area, the client will have to send the jwt token.
  • The next step is to implement a middleware that will check if the jwt token is valid. If it is valid, the user will be able to access the private area.

Middleware

JWT verification middleware

  • In the same structure as the routes directory, create a new folder called middleware. Inside this folder, create a new file called authorization.ts.
  • Paste the following code inside the authorization.ts file:
    We are going to go through this middleware function right after.
jwtGenerator.ts
import jwt from "jsonwebtoken";
import dotenv from "dotenv";
dotenv.config();
 
const authorization = (req, res, next) => {
  const token = req.header("token");
  if (!token) {
    return res.status(403).json("Not Authorized, no token was provided");
  }
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET);
    req.user = payload.user;
    next(); // continue to the next middleware method
  } catch (err) {
    res.status(403).json("Token is not valid");
  }
}
 
export default authorization;

Explanation

  1. The authorization function is defined with three parameters: req for the request object, res for the response object, and next to move on to the next middleware method in the stack.
  2. The req.header("token") method is used to extract the token from the header of the request.
  3. If no token is provided, the function returns a 403 status code with a message stating that the user is not authorized.
  4. If a token is provided, the jwt.verify method is used to verify its validity by checking if it matches the secret stored in the .envfile.
  5. If the token is valid, the payload of the token (which is assumed to contain a "user" object) is extracted and stored in the req.user property.
  6. Finally, the next() method is called to move on to the next middleware method in the stack.

Input validation middleware

  • The function is going to check the validity of the data received in HTTP requests for user registration and login.
  • Create a new file called inputValidation.ts inside middleware folder and paste the following code inside it:
    We are going to go through this middleware function right after.
inputValidation.ts
module.exports = (req, res, next) => {
  const {
    email,
    password,
    firstname,
    lastname,
    birthdate,
    phone,
    sex,
    birthnumber,
  } = req.body;
 
  function validEmail(email) {
    return /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email);
  }
 
  if (req.path === "/register") {
    if (
      ![
        email,
        password,
        firstname,
        lastname,
        birthdate,
        phone,
        sex,
        birthnumber,
      ].every(Boolean)
    ) {
      return res.status(401).json("Some required fields are not filled in");
    } else if (!validEmail(email)) {
      return res.status(401).json("Email has invalid format");
    }
  } else if (req.path === "/login") {
    if (![email, password].every(Boolean)) {
      return res.status(401).json("Some required fields are not filled in");
    } else if (!validEmail(email)) {
      return res.status(401).json("Email has invalid format");
    }
  }
  next();
};

Explanation

  1. It extracts the fields from the request body using destructuring.
  2. The function validEmail() uses a regular expression to check if the email is in a valid format.
  3. If the path of the request is /register, the middleware checks if all the required fields have been filled in. If all required fields are present, it checks if the email is valid by calling the validEmail() function.
  4. If the path of the request is /login, it checks if the email and password fields are filled in and if the email is valid.
  5. Finally, it calls the next() function to pass control to the next middleware function in the chain.

Using the middleware

  • Navigate to the file jwtAuth.ts
  • Import the middleware functions:
jwtAuth.ts
import authorization from "../middleware/authorization";
const inputValidation = require("../middleware/inputValidation");
  • Adjust the definitions of register and login routes by adding the middleware functions:
jwtAuth.ts
router.post("/register", inputValidation, async (req, res) => {
 
router.post("/login", inputValidation, async (req, res) => {
πŸ’‘

You can modify requests in Postman and check whether the middleware functions for checking the validity of the data received in HTTP requests for user registration and login are working properly.

Summary

  • We have created a middleware function that checks the validity of the data received in HTTP requests for user registration and login.
  • We have created a middleware function that checks if the jwt token is valid. This will be used in the next section, where we will implement the private route.