Skip to main content

Express Authenticate Middleware

#📦 Dependencies

  1. express
  2. http-errors
  3. jsonwebtoken
  4. typescript
  5. winston
  6. zod

#🧑‍💻 Code

#Secure your API with a robust authentication middleware

This middleware is the main entry point for authentication. It verifies the presence of a valid JWT token in the Authorization header and ensures the associated user exists in the database. If the token is invalid or the user is not found, it throws an error with a descriptive message.

authenticate.middleware.ts
import { RequestHandler } from "express";
import createHttpError from "http-errors";
import { decodeJwtToken } from "../../auth/utils/jwt.util";
import logger from "../../logging";
import { findUserById } from "../../users/users.service";
/**
* Authenticates incoming requests by verifying the presence of a valid JWT token in the Authorization header.
*
* @param {express.Request} req - The incoming request object.
* @param {express.Response} res - The outgoing response object.
* @param {express.NextFunction} next - The next middleware function in the stack.
* @throws {createHttpError.Unauthorized} If no Authorization header is present or the token is invalid.
* @throws {createHttpError.NotFound} If the user associated with the token is not found.
*/
const authenticate: RequestHandler = async (req, res, next) => {
const authorizationHeader = req.headers?.authorization;
if (!authorizationHeader) {
//? you can use any logger other than `winston` like `morgan`
logger.errors.error(`Failed authentication try.`);
throw new createHttpError.Unauthorized(`Your are not Authorized.`);
}
const [, jwtToken] = authorizationHeader.split(" ");
const payload = await decodeJwtToken(jwtToken);
//! Use your favourite ORM and Database to fetch user
const targetUser = await findUserById((payload as any).id);
if (!targetUser) {
throw new createHttpError.NotFound( // eslint-disable-next-line
`User with Id: ${(payload as any).id} not Found.`,
);
}
Object.assign(req, {
user: payload,
});
next();
};
export { authenticate };

#JWT Utilities

This module contains utility functions for creating and verifying JSON Web Tokens (JWTs). These functions are used in the authentication middleware to verify the authenticity of incoming requests.

jwt.util.ts
import jwt from "jsonwebtoken";
import { ENV } from "../../../config/env";
/**
* Creates a JSON Web Token (JWT) from the provided payload.
*
* @param {object} payload - The payload to be signed and encoded in the JWT.
* @return {string} The created JWT token.
*/
const createJwtToken = async (payload: object, expiresIn?: string | number) => {
const createdJwtToken = await jwt.sign(payload, ENV.JWT_SECRET, {
expiresIn: expiresIn || "1h",
});
return createdJwtToken;
};
/**
* Decodes a JSON Web Token (JWT) and returns its payload.
*
* @param {string} jwtToken - The JWT token to be decoded.
* @return {object} The decoded payload of the JWT token.
*/
const decodeJwtToken = async (jwtToken: string) => {
const payload = jwt.decode(jwtToken);
return payload;
};
export { createJwtToken, decodeJwtToken };

#ENV variables covered by zod

This snippet shows how to use zod to validate ENV variables. It will throw an error if the variable is not set or doesn’t match the schema.

env.ts
import dotenv from "dotenv";
import { z } from "zod";
dotenv.config();
const MAX_PORT_RANGE = 65536;
const envSchema = z.object({
JWT_SECRET: z.string(),
});
type Env = z.infer<typeof envSchema>;
export const ENV: Env = envSchema.parse(process.env);