← Back to Learn

JWT Implementation Guide

Step-by-step implementation guides for different frameworks and programming languages.

Node.js / Express

Express.js Implementation
// Install: npm install jsonwebtoken express

const express = require('express');
const jwt = require('jsonwebtoken');
const app = express();

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

// Login endpoint
app.post('/api/login', async (req, res) => {
  const { username, password } = req.body;
  
  // Verify credentials
  const user = await verifyUser(username, password);
  if (!user) {
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  
  // Generate token
  const token = jwt.sign(
    { sub: user.id, role: user.role },
    JWT_SECRET,
    { algorithm: 'HS256', expiresIn: '15m' }
  );
  
  res.json({ token });
});

// Protected route 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, JWT_SECRET, { algorithms: ['HS256'] }, (err, decoded) => {
    if (err) {
      return res.status(403).json({ error: 'Invalid token' });
    }
    req.user = decoded;
    next();
  });
}

// Use middleware
app.get('/api/protected', authenticateToken, (req, res) => {
  res.json({ message: 'Protected data', user: req.user });
});

Python / Flask

Flask Implementation
# Install: pip install PyJWT flask

from flask import Flask, request, jsonify
import jwt
import datetime
from functools import wraps

app = Flask(__name__)
JWT_SECRET = 'your-secret-key'

# Login endpoint
@app.route('/api/login', methods=['POST'])
def login():
    username = request.json.get('username')
    password = request.json.get('password')
    
    # Verify credentials
    user = verify_user(username, password)
    if not user:
        return jsonify({'error': 'Invalid credentials'}), 401
    
    # Generate token
    token = jwt.encode({
        'sub': user['id'],
        'role': user['role'],
        'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=15)
    }, JWT_SECRET, algorithm='HS256')
    
    return jsonify({'token': token})

# Authentication decorator
def token_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('Authorization')
        if not token:
            return jsonify({'error': 'No token provided'}), 401
        
        try:
            token = token.split(' ')[1]  # Remove 'Bearer '
            data = jwt.decode(token, JWT_SECRET, algorithms=['HS256'])
            request.user = data
        except jwt.ExpiredSignatureError:
            return jsonify({'error': 'Token expired'}), 401
        except jwt.InvalidTokenError:
            return jsonify({'error': 'Invalid token'}), 401
        
        return f(*args, **kwargs)
    return decorated

# Protected route
@app.route('/api/protected')
@token_required
def protected():
    return jsonify({'message': 'Protected data', 'user': request.user})

React / Frontend

React Implementation
// Install: npm install axios

import axios from 'axios';

// Store token in memory (not localStorage)
let accessToken = null;
let refreshToken = null;

// Login function
async function login(username, password) {
  try {
    const response = await axios.post('/api/login', {
      username,
      password
    });
    
    accessToken = response.data.accessToken;
    refreshToken = response.data.refreshToken;
    
    // Set default Authorization header
    axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
    
    return response.data;
  } catch (error) {
    throw error;
  }
}

// Axios interceptor for automatic token refresh
axios.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;
    
    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;
      
      try {
        // Refresh token
        const response = await axios.post('/api/auth/refresh', {
          refreshToken
        });
        
        accessToken = response.data.accessToken;
        axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
        
        // Retry original request
        originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;
        return axios(originalRequest);
      } catch (refreshError) {
        // Refresh failed - redirect to login
        window.location.href = '/login';
        return Promise.reject(refreshError);
      }
    }
    
    return Promise.reject(error);
  }
);

// Logout function
function logout() {
  accessToken = null;
  refreshToken = null;
  delete axios.defaults.headers.common['Authorization'];
  window.location.href = '/login';
}

Next.js / API Routes

Next.js Implementation
// pages/api/protected.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import jwt from 'jsonwebtoken';

const JWT_SECRET = process.env.JWT_SECRET!;

// Middleware function
export function verifyToken(req: NextApiRequest) {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    throw new Error('No token provided');
  }
  
  const token = authHeader.substring(7);
  const decoded = jwt.verify(token, JWT_SECRET, {
    algorithms: ['HS256']
  }) as { sub: string; role: string };
  
  return decoded;
}

// Protected API route
export default function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  try {
    const user = verifyToken(req);
    res.status(200).json({ message: 'Protected data', user });
  } catch (error) {
    res.status(401).json({ error: 'Unauthorized' });
  }
}

// pages/api/login.ts
import jwt from 'jsonwebtoken';

export default function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }
  
  const { username, password } = req.body;
  
  // Verify credentials
  if (username === 'user' && password === 'pass') {
    const token = jwt.sign(
      { sub: 'user-id', role: 'user' },
      process.env.JWT_SECRET,
      { algorithm: 'HS256', expiresIn: '15m' }
    );
    
    res.status(200).json({ token });
  } else {
    res.status(401).json({ error: 'Invalid credentials' });
  }
}

General Implementation Steps

  1. Install JWT library for your language/framework
  2. Set up environment variables for secrets
  3. Create login endpoint that generates tokens
  4. Implement authentication middleware for protected routes
  5. Add token refresh mechanism for long-lived sessions
  6. Implement logout with token revocation
  7. Add error handling for expired/invalid tokens
  8. Test all scenarios including edge cases