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:
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
User logs in with email and password
Server validates credentials
Server generates JWT token
Client stores token (localStorage or cookies)
Client sends token in Authorization header
Server verifies token before giving access
Real-World Example
Imagine a shopping app:
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.