Skip to main content

Command Palette

Search for a command to run...

JWT Authentication in Node.js Explained Simply

Updated
5 min read
JWT Authentication in Node.js Explained Simply

Introduction

Node.js offers multiple approaches for user authentication, one of which is JWT (JSON Web Token) authentication.

It is a widely used and recommended approach because it follows a stateless authentication model, making it well-suited for scalable systems and microservice architectures.

In this article, we will understand the complete flow of JWT authentication how a JWT token is created, how it is verified, and how it is used to authenticate users.


What Authentication Means?

Authentication refers to the process of verifying that a fact or document is genuine. In computer science, it is typically associated with verifying a user’s identity.

In a typical authentication flow, a user provides credentials such as a username and password, which the server then verifies. This approach is used in almost every web and mobile application.

Credentials like a username and password are considered an authentication factor.


What JWT is?

A JSON Web Token (JWT) is a secure way to send information between a client and a server. It is mainly used in web applications and APIs to verify users and prevent unauthorized access.

In a Node.js application, the jsonwebtoken package is used to create JWT tokens. A token is generated using a secret key and a payload (typically user data like userId or role) and is sent to the client side, usually stored in cookies (preferably HttpOnly) or local storage.

Whenever a user logs in, the server first verifies the username and password. If the credentials are valid, a JWT token is created and sent to the client.

Whenever the user makes a request to the server, the token travels along with it (via cookies or Authorization header). The server first verifies the token using the secret key. If the token is valid, the request is processed further; otherwise, it is rejected.

JWT follows a stateless authentication model, so the token is not stored in the database (except in special cases like blacklisting or refresh token handling). This is how the JWT authentication flow works.


JWT Structure

JWT has 3 parts seprated by dots(.)

  • Header

  • Payload

  • Signature

The header contains metadata about the token, including the signing algorithm and token type here metadata means data about data.

  • alg: Algorithm used for signing (e.g., HS256, RS256).

  • typ: Token type, always "JWT".

Payload

The payload contains the information about the user also called as a claim and some additional information including the timestamp at which it was issued and the expiry time of the token.

Common claim types:

  • iss (Issuer): Identifies who issued the token.

  • sub (Subject): Represents the user or entity the token is about.

  • aud (Audience): Specifies the intended recipient.

  • exp (Expiration): Defines when the token expires.

  • iat (Issued At): Timestamp when the token was created.

  • nbf (Not Before): Specifies when the token becomes valid.

Signature

Signature is the secret key used to create and verify the token it is generate using header and payload. a signature is a random string stored in .env file.

Example: WflSxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c


Login Flow Using JWT

Let's understand the complete flow of JWT

  • User enters credentials (username and password) to log in.

  • Server verifies credentials using the database.

  • After successful verification, the server generates a JWT token (secret key + payload).

  • The server may store token/refresh token in DB (for revocation/session tracking).

  • Token is sent to the client (cookie or Authorization header).

  • Whenever the user makes a request, the token travels along with it.

  • On protected routes, the server:

    • Verifies token using secret key

    • (Optional) checks DB to ensure token/session is still valid (not revoked)

  • If valid → request processed; else → rejected.


Protecting Routes Using Tokens

When we need to authorize a user for a specific or protected route, we place an authentication middleware between the route path and the controller. This ensures that the token is verified before the request reaches the controller.

First, the token is verified. If the token is valid, the request is forwarded to the controller; otherwise, the request is rejected.

To protect routes, we create an authentication middleware where we verify the token, like this:

// auth.middleware.js
import jwt from "jsonwebtoken";

export const authMiddleware = (req, res, next) => {
  try {
    let token;

    if (req.cookies?.token) {
      token = req.cookies.token;
    } else if (req.headers.authorization?.startsWith('Bearer ')) {
      token = req.headers.authorization.split(' ')[1];
    }

    if (!token) {
      return res.status(401).json({ message: 'Unauthorized: No token' });
    }

    const decoded = jwt.verify(token, process.env.JWT_SECRET);
 
    req.user = decoded;

    next();
  } catch (err) {
    return res.status(401).json({ message: 'Unauthorized: Invalid token' });
  }
};

This is how a auth middleware look like and here is how we put middleware in the secure route;

// routes/user.routes.js
import express from 'express';
import authMiddleware from '../middleware/auth.middleware.js';

const router = express.Router();

// Secure route
router.get('/profile', authMiddleware, (req, res) => {
  res.json({
    message: 'Protected route',
    user: req.user,
  });
});

export default router;

Conclusion

As you start building applications, you gradually understand business use cases better. In the beginning, you may not know exactly where to apply middleware or which routes should be protected. But over time, with experience, these decisions become clearer.

So, that was all about JWT and authentication.

Hope you liked this article❤️