Node.js10 min read

Authentication with JWT in Node.js

Implement JWT authentication in Node.js. Learn token generation, verification, and protected routes.

Sarah Chen
December 19, 2025
0.0k0

Authentication with JWT in Node.js

JWT (JSON Web Token) is the standard for API authentication. No sessions, stateless, scalable.

How JWT Works

1. User logs in with email/password
2. Server verifies, generates JWT
3. Server sends JWT to client
4. Client stores JWT (localStorage/cookie)
5. Client sends JWT with every request
6. Server verifies JWT, allows access

JWT Structure

header.payload.signature

eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOjF9.abc123signature

Setup

npm install express jsonwebtoken bcryptjs

Generate Token

const jwt = require('jsonwebtoken');

const SECRET = process.env.JWT_SECRET || 'your-secret-key';

function generateToken(user) {
  return jwt.sign(
    { userId: user.id, email: user.email },
    SECRET,
    { expiresIn: '7d' }
  );
}

Verify Token

function verifyToken(token) {
  try {
    return jwt.verify(token, SECRET);
  } catch (error) {
    return null;
  }
}

Auth Middleware

function authMiddleware(req, res, next) {
  const authHeader = req.headers.authorization;
  
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'No token provided' });
  }
  
  const token = authHeader.split(' ')[1];
  const decoded = verifyToken(token);
  
  if (!decoded) {
    return res.status(401).json({ error: 'Invalid token' });
  }
  
  req.user = decoded;
  next();
}

Password Hashing

const bcrypt = require('bcryptjs');

// Hash password (registration)
async function hashPassword(password) {
  return bcrypt.hash(password, 10);
}

// Compare password (login)
async function comparePassword(password, hash) {
  return bcrypt.compare(password, hash);
}

Complete Auth Routes

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

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

const SECRET = 'your-secret-key';
const users = [];  // In-memory (use database in production)

// Register
app.post('/api/register', async (req, res) => {
  const { email, password } = req.body;
  
  // Check if user exists
  if (users.find(u => u.email === email)) {
    return res.status(400).json({ error: 'Email already registered' });
  }
  
  // Hash password
  const hashedPassword = await bcrypt.hash(password, 10);
  
  // Create user
  const user = {
    id: users.length + 1,
    email,
    password: hashedPassword
  };
  users.push(user);
  
  // Generate token
  const token = jwt.sign({ userId: user.id }, SECRET, { expiresIn: '7d' });
  
  res.status(201).json({ token, user: { id: user.id, email } });
});

// Login
app.post('/api/login', async (req, res) => {
  const { email, password } = req.body;
  
  // Find user
  const user = users.find(u => u.email === email);
  if (!user) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  
  // Check password
  const valid = await bcrypt.compare(password, user.password);
  if (!valid) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  
  // Generate token
  const token = jwt.sign({ userId: user.id }, SECRET, { expiresIn: '7d' });
  
  res.json({ token, user: { id: user.id, email: user.email } });
});

// Auth middleware
function auth(req, res, next) {
  const authHeader = req.headers.authorization;
  if (!authHeader?.startsWith('Bearer ')) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  
  try {
    const token = authHeader.split(' ')[1];
    req.user = jwt.verify(token, SECRET);
    next();
  } catch {
    res.status(401).json({ error: 'Invalid token' });
  }
}

// Protected route
app.get('/api/profile', auth, (req, res) => {
  const user = users.find(u => u.id === req.user.userId);
  res.json({ id: user.id, email: user.email });
});

app.listen(3000);

Frontend Usage

// Login
const response = await fetch('/api/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email, password })
});
const { token } = await response.json();
localStorage.setItem('token', token);

// Authenticated request
const profile = await fetch('/api/profile', {
  headers: {
    'Authorization': `Bearer ${localStorage.getItem('token')}`
  }
});

Key Takeaway

JWT enables stateless authentication. Hash passwords with bcrypt, generate tokens on login, verify tokens in middleware. Store tokens client-side, send in Authorization header. Simple and scalable!

#Node.js#JWT#Authentication#Security#Intermediate