Angular  

Building Authentication with JWT in Node.js

Introduction

Authentication is a crucial part of any modern web application. Whether you're building a REST API, a SaaS product, or a mobile backend, you need a secure way to verify users.

One of the most widely used approaches today is JWT (JSON Web Token) authentication. It allows you to securely transmit user identity between client and server in a stateless way.

In this guide, we will implement JWT-based authentication using Node.js in a simple and practical way.

What is JWT?

JWT (JSON Web Token) is a compact, URL-safe token format used for authentication and authorization.

A JWT typically consists of three parts:

  • Header

  • Payload

  • Signature

Real-world analogy: Think of JWT like a digital ID card. Once issued, the client carries it and shows it to access protected resources.

Install Dependencies

First, install the required packages:

npm install express jsonwebtoken bcryptjs

Project Setup

Basic Express setup:

const express = require("express");
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");

const app = express();
app.use(express.json());

const SECRET_KEY = "yourSecretKey";

Create JWT Token

This function generates a token when the user logs in successfully:

function generateToken(user) {
  return jwt.sign({ id: user.id }, SECRET_KEY, { expiresIn: "1h" });
}

Login Route

Here we validate user credentials and generate a token:

app.post("/login", async (req, res) => {
  const { email, password } = req.body;

  // Simulated user (in real apps, fetch from DB)
  const user = { id: 1, email, password: "123456" };

  if (password !== user.password) {
    return res.status(401).send("Invalid credentials");
  }

  const token = generateToken(user);
  res.json({ token });
});

Secure Password (Recommended Improvement)

Instead of storing plain passwords, use hashing:

const hashedPassword = await bcrypt.hash("123456", 10);
const isMatch = await bcrypt.compare(password, hashedPassword);

Middleware to Verify Token

This middleware protects routes by verifying JWT:

function authMiddleware(req, res, next) {
  const token = req.headers["authorization"];

  if (!token) return res.sendStatus(403);

  jwt.verify(token, SECRET_KEY, (err, decoded) => {
    if (err) return res.sendStatus(401);
    req.user = decoded;
    next();
  });
}

Protected Route Example

app.get("/profile", authMiddleware, (req, res) => {
  res.json({ message: "Protected data", user: req.user });
});

Step-by-Step Flow

  1. User logs in with email and password

  2. Server validates credentials

  3. Server generates JWT token

  4. Client stores token (localStorage or cookies)

  5. Client sends token in Authorization header

  6. Server verifies token before giving access

Real-World Example

Imagine a shopping app:

  • Without JWT: Server checks login every time (slow and heavy)

  • With JWT: User logs in once and reuses token for all requests (fast and scalable)

Advantages of JWT Authentication

  • Stateless (no session storage needed)

  • Scalable for large applications

  • Works well with APIs and microservices

  • Easy integration with frontend frameworks

Disadvantages

  • Token cannot be easily revoked (unless using blacklist)

  • Larger payload compared to session IDs

  • Requires careful handling of secret keys

Best Practices

  • Always store SECRET_KEY in environment variables

  • Use HTTPS to protect tokens

  • Set token expiration time

  • Use refresh tokens for long sessions

  • Avoid storing sensitive data in JWT payload

Conclusion

You now have a working JWT authentication system in Node.js. By combining Express, JWT, and secure password handling, you can build scalable and secure authentication for real-world applications.

Start implementing this in your projects and gradually enhance it with refresh tokens, role-based access, and database integration.