← 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
- Install JWT library for your language/framework
- Set up environment variables for secrets
- Create login endpoint that generates tokens
- Implement authentication middleware for protected routes
- Add token refresh mechanism for long-lived sessions
- Implement logout with token revocation
- Add error handling for expired/invalid tokens
- Test all scenarios including edge cases