JWT Authentication in Node.js

What is JWT?

JWT (JSON Web Token) is a compact, URL-safe token format for securely transmitting information between parties. Commonly used for authentication and authorization.

JWT Structure

header.payload.signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJ1c2VySWQiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Parts:

  1. Header: Algorithm and token type
  2. Payload: Claims (user data)
  3. Signature: Verification signature

Installation

npm install jsonwebtoken bcryptjs

Creating JWT

const jwt = require('jsonwebtoken');

// Generate token
const token = jwt.sign(
  { userId: user.id, email: user.email },
  process.env.JWT_SECRET,
  { expiresIn: '1h' }
);

console.log(token);

Verifying JWT

try {
  const decoded = jwt.verify(token, process.env.JWT_SECRET);
  console.log(decoded); // { userId, email, iat, exp }
} catch (err) {
  console.error('Invalid token');
}

Complete Authentication Example

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

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

// Mock user database
const users = [];

// Register
app.post('/register', async (req, res) => {
  try {
    const { email, password } = req.body;
    
    // Hash password
    const hashedPassword = await bcrypt.hash(password, 10);
    
    // Save user
    const user = {
      id: users.length + 1,
      email,
      password: hashedPassword
    };
    users.push(user);
    
    res.status(201).json({ message: 'User created' });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Login
app.post('/login', async (req, res) => {
  try {
    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' });
    }
    
    // Verify password
    const validPassword = await bcrypt.compare(password, user.password);
    if (!validPassword) {
      return res.status(401).json({ error: 'Invalid credentials' });
    }
    
    // Generate token
    const token = jwt.sign(
      { userId: user.id, email: user.email },
      process.env.JWT_SECRET,
      { expiresIn: '1h' }
    );
    
    res.json({ token });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

// Protected route
app.get('/profile', authenticateToken, (req, res) => {
  res.json({ user: req.user });
});

// Middleware
function authenticateToken(req, res, next) {
  const authHeader = req.headers['authorization'];
  const token = authHeader && authHeader.split(' ')[1];
  
  if (!token) {
    return res.status(401).json({ error: 'No token provided' });
  }
  
  jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
    if (err) {
      return res.status(403).json({ error: 'Invalid token' });
    }
    req.user = user;
    next();
  });
}

Refresh Tokens

const refreshTokens = [];

// Login with refresh token
app.post('/login', async (req, res) => {
  // ... authentication logic
  
  const accessToken = jwt.sign(
    { userId: user.id },
    process.env.JWT_SECRET,
    { expiresIn: '15m' }
  );
  
  const refreshToken = jwt.sign(
    { userId: user.id },
    process.env.REFRESH_TOKEN_SECRET,
    { expiresIn: '7d' }
  );
  
  refreshTokens.push(refreshToken);
  
  res.json({ accessToken, refreshToken });
});

// Refresh access token
app.post('/token', (req, res) => {
  const { refreshToken } = req.body;
  
  if (!refreshToken || !refreshTokens.includes(refreshToken)) {
    return res.status(403).json({ error: 'Invalid refresh token' });
  }
  
  jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
    if (err) {
      return res.status(403).json({ error: 'Invalid token' });
    }
    
    const accessToken = jwt.sign(
      { userId: user.userId },
      process.env.JWT_SECRET,
      { expiresIn: '15m' }
    );
    
    res.json({ accessToken });
  });
});

// Logout
app.post('/logout', (req, res) => {
  const { refreshToken } = req.body;
  const index = refreshTokens.indexOf(refreshToken);
  if (index > -1) {
    refreshTokens.splice(index, 1);
  }
  res.json({ message: 'Logged out' });
});

Best Practices

  1. Use HTTPS in production
  2. Store tokens securely (httpOnly cookies)
  3. Set appropriate expiration times
  4. Implement refresh tokens for long sessions
  5. Never store sensitive data in payload
  6. Use strong secrets for signing
  7. Validate tokens on every request

Interview Tips

  • Explain JWT structure: Header, payload, signature
  • Show token generation: jwt.sign()
  • Demonstrate verification: jwt.verify()
  • Discuss security: HTTPS, secrets, expiration
  • Mention refresh tokens: Long-lived sessions
  • Show middleware: Authentication middleware

Summary

JWT is a token-based authentication method. Generate tokens with jwt.sign(), verify with jwt.verify(). Include userId in payload, set expiration time. Use middleware to protect routes. Implement refresh tokens for better security.

Test Your Knowledge

Take a quick quiz to test your understanding of this topic.

Test Your Node.js Knowledge

Ready to put your skills to the test? Take our interactive Node.js quiz and get instant feedback on your answers.