DEV Community

Tanmay Gupta
Tanmay Gupta

Posted on

Authentication in Express Using JWT (JSON Web Tokens)

Securing your backend routes is crucial when building modern web applications. One of the most common and secure ways to handle authentication is by using JWT (JSON Web Tokens).

In this guide, you’ll learn:

  • What JWT is
  • How to implement login/signup
  • How to protect routes using tokens in an Express.js app
  • Adding encryption using bcryptjs to store hashed passwords

What is JWT?

JWT (JSON Web Token) is a compact, URL-safe token used to securely transmit information between parties. It has three parts:

  1. Header – Type and algorithm
  2. Payload – User info (e.g. ID, email)
  3. Signature – Verifies the token's authenticity

A sample token looks like:

eyJhbGciOi... (header). (payload). (signature)
Enter fullscreen mode Exit fullscreen mode

Step 1: Setup

Install required packages:

npm install express jsonwebtoken bcryptjs dotenv
Enter fullscreen mode Exit fullscreen mode

Also set up your project:

npm init -y
Enter fullscreen mode Exit fullscreen mode

Create a basic server.js:

import express from 'express';
import dotenv from 'dotenv';

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

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
Enter fullscreen mode Exit fullscreen mode

Step 2: Mock User Database (In-Memory for Demo)

const users = []; // This would be replaced with a real database
Enter fullscreen mode Exit fullscreen mode

Step 3: Signup Route (Register User)

import bcrypt from 'bcryptjs';

app.post('/signup', async (req, res) => {
  const { username, password } = req.body;

  const existing = users.find(u => u.username === username);
  if (existing) return res.status(400).json({ message: 'User already exists' });

  const hashedPassword = await bcrypt.hash(password, 10);
  users.push({ username, password: hashedPassword });

  res.status(201).json({ message: 'User registered successfully' });
});
Enter fullscreen mode Exit fullscreen mode

Step 4: Login Route (Generate JWT Token)

import jwt from 'jsonwebtoken';

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

  const user = users.find(u => u.username === username);
  if (!user) return res.status(400).json({ message: 'Invalid credentials' });

  const isMatch = await bcrypt.compare(password, user.password);
  if (!isMatch) return res.status(400).json({ message: 'Invalid credentials' });

  const token = jwt.sign({ username }, process.env.JWT_SECRET, {
    expiresIn: '1h'
  });

  res.json({ token });
});
Enter fullscreen mode Exit fullscreen mode

.env file:

JWT_SECRET=your_jwt_secret_key
Enter fullscreen mode Exit fullscreen mode

Step 5: Middleware to Protect Routes

const authenticateToken = (req, res, next) => {
  const authHeader = req.headers.authorization;
  const token = authHeader && authHeader.split(' ')[1]; // Bearer <token>

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

  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    req.user = user;
    next();
  });
};
Enter fullscreen mode Exit fullscreen mode

Step 6: Protected Route

app.get('/profile', authenticateToken, (req, res) => {
  res.json({ message: `Hello, ${req.user.username}!` });
});
Enter fullscreen mode Exit fullscreen mode

Testing the Flow

  1. POST /signup – Register a user
  2. POST /login – Get JWT token
  3. GET /profile – Add Authorization: Bearer <token> header

Summary

Endpoint Purpose Protected?
POST /signup Register new users
POST /login Log in and get token
GET /profile Access user data ✅ (JWT)

Final Thoughts

JWT is a powerful tool for stateless authentication in Express. It’s ideal for APIs where you need to:

  • Validate users
  • Protect routes
  • Handle sessions without storing them server-side

Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.