jsonwebtoken (Node.js)

authentication libraryNode.jsJWTJSON Web TokenAuth0securitysigningverification

Library

jsonwebtoken (Node.js)

Overview

jsonwebtoken is a JSON Web Token (JWT) library for Node.js developed and maintained by Auth0. As of 2025, it has become one of the most popular JWT libraries with over 28 million weekly downloads on npm and is used by over 34,000 projects. As an RFC 7519-compliant JWT implementation, it supports both symmetric and asymmetric signing algorithms, with full support for major algorithms including HS256, RS256, and ES256. In addition to basic functions for token generation (jwt.sign), verification (jwt.verify), and decoding (jwt.decode), it provides expiration time settings, custom claims, and asynchronous processing support. It integrates easily with web frameworks like Express.js, Hapi, and Koa, and has been widely adopted as an industry standard for building authentication and authorization systems.

Details

jsonwebtoken 9.x series supports Node.js 12 and above, providing high-performance JWT processing leveraging the latest JavaScript (ES2020+) features. As core functionality, it provides three interfaces: Promise-based asynchronous API, callback-based traditional API, and synchronous processing API, accommodating diverse development styles. From a security perspective, it supports a wide range of signing algorithms including HMAC-SHA256 (HS256), RSA-SHA256 (RS256), and ECDSA-SHA256 (ES256), and also supports key management and rotation. With performance optimization, it achieves high-speed operation even when processing large volumes of tokens, making it applicable to enterprise-level applications.

Key Features

  • Comprehensive JWT Implementation: RFC 7519 fully compliant token generation, verification, and decoding functions
  • Diverse Signing Algorithms: Support for HS256/HS384/HS512, RS256/RS384/RS512, ES256/ES384/ES512
  • Flexible API Design: Three interfaces - synchronous, asynchronous, and Promise-based
  • Advanced Security: Expiration, issuer, audience validation and custom claims support
  • Excellent Compatibility: Integration track record with major Node.js frameworks
  • Enterprise Ready: High performance and reliability in large-scale environments

Advantages and Disadvantages

Advantages

  • High reliability and stability through long-term maintenance track record by Auth0
  • Rich implementation examples and information volume with over 28 million weekly npm downloads
  • Complete compatibility with other JWT implementations guaranteed by RFC 7519 full compliance
  • Support for diverse development styles through three API patterns - synchronous, asynchronous, and Promise
  • Flexible response to security requirements through wide range of signing algorithm support from HS256 to ES512
  • Easy integration with web frameworks like Express.js for high development efficiency

Disadvantages

  • Node.js-specific library, cannot be used directly in browser environments
  • CPU usage may increase when verifying large volumes of tokens
  • Key management complexity increases when using asymmetric signatures (RS256, etc.)
  • TypeScript type definitions provided in separate package (@types/jsonwebtoken)
  • Improper security configuration may create vulnerabilities
  • Additional implementation required for complex claim validation logic

Reference Pages

Usage Examples

Basic Setup and Dependency Installation

# Install jsonwebtoken library
npm install jsonwebtoken

# Install type definitions for TypeScript usage
npm install --save-dev @types/jsonwebtoken

# Additional packages for security enhancement (optional)
npm install crypto
npm install dotenv  # For environment variable management
// Basic require statement (CommonJS)
const jwt = require('jsonwebtoken');

// ES6 import statement (when using modules)
import jwt from 'jsonwebtoken';

// Typed import for TypeScript environment
import * as jwt from 'jsonwebtoken';
// package.json configuration example
{
  "name": "jwt-auth-app",
  "version": "1.0.0",
  "dependencies": {
    "jsonwebtoken": "^9.0.2",
    "express": "^4.18.2",
    "dotenv": "^16.3.1"
  },
  "devDependencies": {
    "@types/jsonwebtoken": "^9.0.3",
    "@types/node": "^20.5.0"
  }
}

JWT Token Generation and Custom Claims Configuration

// JWTTokenService.js - Token generation service
const jwt = require('jsonwebtoken');
const crypto = require('crypto');

class JWTTokenService {
    constructor() {
        // Get secret key from environment variables (required in production)
        this.secretKey = process.env.JWT_SECRET || this.generateSecretKey();
        this.issuer = process.env.JWT_ISSUER || 'your-app-name';
        this.audience = process.env.JWT_AUDIENCE || 'your-app-users';
    }
    
    // Generate secure secret key
    generateSecretKey() {
        return crypto.randomBytes(64).toString('hex');
    }
    
    // Basic JWT token generation
    generateToken(payload, options = {}) {
        // Default options configuration
        const defaultOptions = {
            expiresIn: '1h',           // Valid for 1 hour
            issuer: this.issuer,       // Issuer
            audience: this.audience,   // Audience
            algorithm: 'HS256'         // Signing algorithm
        };
        
        const finalOptions = { ...defaultOptions, ...options };
        
        try {
            // Synchronous token generation
            const token = jwt.sign(payload, this.secretKey, finalOptions);
            console.log('JWT token generated successfully');
            return token;
        } catch (error) {
            console.error('JWT token generation failed:', error.message);
            throw new Error('Token generation failed');
        }
    }
    
    // Asynchronous token generation (Callback version)
    generateTokenAsync(payload, options = {}, callback) {
        const defaultOptions = {
            expiresIn: '1h',
            issuer: this.issuer,
            audience: this.audience,
            algorithm: 'HS256'
        };
        
        const finalOptions = { ...defaultOptions, ...options };
        
        jwt.sign(payload, this.secretKey, finalOptions, (error, token) => {
            if (error) {
                console.error('Async JWT token generation failed:', error.message);
                return callback(error, null);
            }
            
            console.log('Async JWT token generated successfully');
            callback(null, token);
        });
    }
    
    // Promise-based asynchronous token generation
    generateTokenPromise(payload, options = {}) {
        return new Promise((resolve, reject) => {
            this.generateTokenAsync(payload, options, (error, token) => {
                if (error) {
                    reject(error);
                } else {
                    resolve(token);
                }
            });
        });
    }
    
    // User authentication token generation
    generateUserToken(user) {
        const payload = {
            sub: user.id,                    // Subject (User ID)
            username: user.username,
            email: user.email,
            roles: user.roles || ['user'],
            permissions: user.permissions || [],
            iat: Math.floor(Date.now() / 1000) // Issued at time
        };
        
        return this.generateToken(payload, {
            expiresIn: '2h',
            subject: user.id
        });
    }
    
    // Refresh token generation
    generateRefreshToken(userId) {
        const payload = {
            sub: userId,
            type: 'refresh',
            iat: Math.floor(Date.now() / 1000)
        };
        
        return this.generateToken(payload, {
            expiresIn: '7d',  // Valid for 7 days
            subject: userId
        });
    }
    
    // Admin-only token generation
    generateAdminToken(admin) {
        const payload = {
            sub: admin.id,
            username: admin.username,
            email: admin.email,
            roles: ['admin'],
            permissions: admin.permissions || ['read', 'write', 'delete'],
            isAdmin: true,
            department: admin.department,
            iat: Math.floor(Date.now() / 1000)
        };
        
        return this.generateToken(payload, {
            expiresIn: '1h',  // Short expiration for admin tokens
            audience: this.audience + '-admin'
        });
    }
    
    // Temporary access token generation (password reset, etc.)
    generateTemporaryToken(userId, purpose) {
        const payload = {
            sub: userId,
            purpose: purpose,        // 'password-reset', 'email-verify', etc.
            temp: true,
            iat: Math.floor(Date.now() / 1000)
        };
        
        return this.generateToken(payload, {
            expiresIn: '15m',  // Valid for 15 minutes only
            audience: this.audience + '-temp'
        });
    }
}

// Usage examples
const tokenService = new JWTTokenService();

// User information
const user = {
    id: '12345',
    username: 'johndoe',
    email: '[email protected]',
    roles: ['user', 'premium'],
    permissions: ['read', 'write']
};

// Various token generation examples
const userToken = tokenService.generateUserToken(user);
const refreshToken = tokenService.generateRefreshToken(user.id);
const resetToken = tokenService.generateTemporaryToken(user.id, 'password-reset');

console.log('User Token:', userToken);
console.log('Refresh Token:', refreshToken);
console.log('Reset Token:', resetToken);

module.exports = JWTTokenService;

JWT Token Verification and Security Checks

// JWTVerificationService.js - Token verification service
const jwt = require('jsonwebtoken');

class JWTVerificationService {
    constructor(secretKey, options = {}) {
        this.secretKey = secretKey || process.env.JWT_SECRET;
        this.issuer = options.issuer || process.env.JWT_ISSUER;
        this.audience = options.audience || process.env.JWT_AUDIENCE;
        this.algorithms = options.algorithms || ['HS256'];
    }
    
    // Basic token verification
    verifyToken(token, options = {}) {
        const defaultOptions = {
            issuer: this.issuer,
            audience: this.audience,
            algorithms: this.algorithms,
            clockTolerance: 30,  // 30 second clock tolerance
            ignoreExpiration: false,
            ignoreNotBefore: false
        };
        
        const finalOptions = { ...defaultOptions, ...options };
        
        try {
            // Synchronous token verification
            const decoded = jwt.verify(token, this.secretKey, finalOptions);
            console.log('JWT token verified successfully');
            return {
                success: true,
                payload: decoded,
                error: null
            };
        } catch (error) {
            console.error('JWT token verification failed:', error.message);
            return {
                success: false,
                payload: null,
                error: this.categorizeError(error)
            };
        }
    }
    
    // Asynchronous token verification (Callback version)
    verifyTokenAsync(token, options = {}, callback) {
        const defaultOptions = {
            issuer: this.issuer,
            audience: this.audience,
            algorithms: this.algorithms,
            clockTolerance: 30
        };
        
        const finalOptions = { ...defaultOptions, ...options };
        
        jwt.verify(token, this.secretKey, finalOptions, (error, decoded) => {
            if (error) {
                console.error('Async JWT token verification failed:', error.message);
                return callback({
                    success: false,
                    payload: null,
                    error: this.categorizeError(error)
                });
            }
            
            console.log('Async JWT token verified successfully');
            callback({
                success: true,
                payload: decoded,
                error: null
            });
        });
    }
    
    // Promise-based asynchronous token verification
    verifyTokenPromise(token, options = {}) {
        return new Promise((resolve, reject) => {
            this.verifyTokenAsync(token, options, (result) => {
                if (result.success) {
                    resolve(result);
                } else {
                    reject(result);
                }
            });
        });
    }
    
    // Error categorization
    categorizeError(error) {
        if (error.name === 'TokenExpiredError') {
            return {
                type: 'EXPIRED',
                message: 'Token has expired',
                expiredAt: error.expiredAt
            };
        } else if (error.name === 'JsonWebTokenError') {
            return {
                type: 'INVALID',
                message: 'Token is invalid',
                details: error.message
            };
        } else if (error.name === 'NotBeforeError') {
            return {
                type: 'NOT_ACTIVE',
                message: 'Token not active',
                date: error.date
            };
        } else {
            return {
                type: 'UNKNOWN',
                message: 'Unknown verification error',
                details: error.message
            };
        }
    }
    
    // Token decoding (without verification)
    decodeToken(token, options = {}) {
        const defaultOptions = {
            complete: false,  // true returns header, payload, signature
            json: true       // return as JSON object
        };
        
        const finalOptions = { ...defaultOptions, ...options };
        
        try {
            const decoded = jwt.decode(token, finalOptions);
            return {
                success: true,
                payload: decoded,
                error: null
            };
        } catch (error) {
            return {
                success: false,
                payload: null,
                error: error.message
            };
        }
    }
    
    // Admin privileges check
    verifyAdminToken(token) {
        const result = this.verifyToken(token, {
            audience: this.audience + '-admin'
        });
        
        if (!result.success) {
            return result;
        }
        
        // Admin privileges check
        if (!result.payload.isAdmin || !result.payload.roles.includes('admin')) {
            return {
                success: false,
                payload: null,
                error: {
                    type: 'INSUFFICIENT_PRIVILEGES',
                    message: 'Admin privileges required'
                }
            };
        }
        
        return result;
    }
    
    // User permissions check
    verifyUserPermissions(token, requiredPermissions = []) {
        const result = this.verifyToken(token);
        
        if (!result.success) {
            return result;
        }
        
        const userPermissions = result.payload.permissions || [];
        const hasAllPermissions = requiredPermissions.every(permission => 
            userPermissions.includes(permission)
        );
        
        if (!hasAllPermissions) {
            return {
                success: false,
                payload: null,
                error: {
                    type: 'INSUFFICIENT_PERMISSIONS',
                    message: 'Required permissions not found',
                    required: requiredPermissions,
                    current: userPermissions
                }
            };
        }
        
        return result;
    }
    
    // Refresh token verification
    verifyRefreshToken(token) {
        const result = this.verifyToken(token);
        
        if (!result.success) {
            return result;
        }
        
        // Refresh token type check
        if (result.payload.type !== 'refresh') {
            return {
                success: false,
                payload: null,
                error: {
                    type: 'INVALID_TOKEN_TYPE',
                    message: 'Not a refresh token'
                }
            };
        }
        
        return result;
    }
    
    // Temporary token verification
    verifyTemporaryToken(token, expectedPurpose) {
        const result = this.verifyToken(token, {
            audience: this.audience + '-temp'
        });
        
        if (!result.success) {
            return result;
        }
        
        // Check if temporary token and purpose matches
        if (!result.payload.temp || result.payload.purpose !== expectedPurpose) {
            return {
                success: false,
                payload: null,
                error: {
                    type: 'INVALID_PURPOSE',
                    message: 'Token purpose mismatch',
                    expected: expectedPurpose,
                    actual: result.payload.purpose
                }
            };
        }
        
        return result;
    }
}

// Usage examples
const verificationService = new JWTVerificationService(process.env.JWT_SECRET, {
    issuer: 'your-app-name',
    audience: 'your-app-users'
});

// Token verification example
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

// Basic verification
const result = verificationService.verifyToken(token);
if (result.success) {
    console.log('Token is valid:', result.payload);
} else {
    console.log('Token verification failed:', result.error);
}

// Admin privileges check
const adminResult = verificationService.verifyAdminToken(token);

// Permissions check
const permissionResult = verificationService.verifyUserPermissions(token, ['read', 'write']);

module.exports = JWTVerificationService;

Express.js Middleware Integration and Authentication Flow

// JWTMiddleware.js - Express.js JWT middleware
const jwt = require('jsonwebtoken');
const JWTVerificationService = require('./JWTVerificationService');

class JWTMiddleware {
    constructor(secretKey, options = {}) {
        this.verificationService = new JWTVerificationService(secretKey, options);
        this.cookieName = options.cookieName || 'auth_token';
        this.headerName = options.headerName || 'authorization';
    }
    
    // Basic authentication middleware
    authenticate() {
        return (req, res, next) => {
            const token = this.extractToken(req);
            
            if (!token) {
                return res.status(401).json({
                    error: 'Authentication required',
                    message: 'No token provided'
                });
            }
            
            const result = this.verificationService.verifyToken(token);
            
            if (!result.success) {
                return res.status(401).json({
                    error: 'Invalid token',
                    message: result.error.message,
                    type: result.error.type
                });
            }
            
            // Add user information to request
            req.user = result.payload;
            req.token = token;
            next();
        };
    }
    
    // Optional authentication middleware
    optionalAuthenticate() {
        return (req, res, next) => {
            const token = this.extractToken(req);
            
            if (!token) {
                req.user = null;
                return next();
            }
            
            const result = this.verificationService.verifyToken(token);
            
            if (result.success) {
                req.user = result.payload;
                req.token = token;
            } else {
                req.user = null;
            }
            
            next();
        };
    }
    
    // Admin privileges check middleware
    requireAdmin() {
        return (req, res, next) => {
            const token = this.extractToken(req);
            
            if (!token) {
                return res.status(401).json({
                    error: 'Authentication required',
                    message: 'Admin access requires token'
                });
            }
            
            const result = this.verificationService.verifyAdminToken(token);
            
            if (!result.success) {
                return res.status(403).json({
                    error: 'Access denied',
                    message: result.error.message,
                    type: result.error.type
                });
            }
            
            req.user = result.payload;
            req.token = token;
            next();
        };
    }
    
    // Permissions check middleware
    requirePermissions(permissions = []) {
        return (req, res, next) => {
            const token = this.extractToken(req);
            
            if (!token) {
                return res.status(401).json({
                    error: 'Authentication required',
                    message: 'Permission check requires token'
                });
            }
            
            const result = this.verificationService.verifyUserPermissions(token, permissions);
            
            if (!result.success) {
                return res.status(403).json({
                    error: 'Insufficient permissions',
                    message: result.error.message,
                    required: result.error.required,
                    current: result.error.current
                });
            }
            
            req.user = result.payload;
            req.token = token;
            next();
        };
    }
    
    // Role check middleware
    requireRoles(roles = []) {
        return (req, res, next) => {
            const token = this.extractToken(req);
            
            if (!token) {
                return res.status(401).json({
                    error: 'Authentication required'
                });
            }
            
            const result = this.verificationService.verifyToken(token);
            
            if (!result.success) {
                return res.status(401).json({
                    error: 'Invalid token',
                    message: result.error.message
                });
            }
            
            const userRoles = result.payload.roles || [];
            const hasRequiredRole = roles.some(role => userRoles.includes(role));
            
            if (!hasRequiredRole) {
                return res.status(403).json({
                    error: 'Insufficient role',
                    message: 'Required role not found',
                    required: roles,
                    current: userRoles
                });
            }
            
            req.user = result.payload;
            req.token = token;
            next();
        };
    }
    
    // Token extraction logic
    extractToken(req) {
        // Extract token from Authorization header
        const authHeader = req.headers[this.headerName];
        if (authHeader && authHeader.startsWith('Bearer ')) {
            return authHeader.substring(7);
        }
        
        // Extract token from Cookie
        if (req.cookies && req.cookies[this.cookieName]) {
            return req.cookies[this.cookieName];
        }
        
        // Extract token from query parameter (deprecated but for emergency use)
        if (req.query && req.query.token) {
            return req.query.token;
        }
        
        return null;
    }
}

// Express.js application integration example
const express = require('express');
const cookieParser = require('cookie-parser');
const JWTTokenService = require('./JWTTokenService');

const app = express();
const tokenService = new JWTTokenService();
const jwtMiddleware = new JWTMiddleware(process.env.JWT_SECRET, {
    issuer: 'your-app-name',
    audience: 'your-app-users'
});

// Basic middleware configuration
app.use(express.json());
app.use(cookieParser());

// Login endpoint
app.post('/auth/login', async (req, res) => {
    try {
        const { username, password } = req.body;
        
        // Authentication logic (use external authentication system in production)
        const user = await authenticateUser(username, password);
        
        if (!user) {
            return res.status(401).json({
                error: 'Authentication failed',
                message: 'Invalid credentials'
            });
        }
        
        // Token generation
        const accessToken = tokenService.generateUserToken(user);
        const refreshToken = tokenService.generateRefreshToken(user.id);
        
        // Set token in cookie
        res.cookie('auth_token', accessToken, {
            httpOnly: true,
            secure: process.env.NODE_ENV === 'production',
            sameSite: 'strict',
            maxAge: 2 * 60 * 60 * 1000 // 2 hours
        });
        
        res.json({
            message: 'Login successful',
            user: {
                id: user.id,
                username: user.username,
                email: user.email,
                roles: user.roles
            },
            tokens: {
                accessToken,
                refreshToken,
                expiresIn: 7200  // 2 hours (seconds)
            }
        });
    } catch (error) {
        res.status(500).json({
            error: 'Internal server error',
            message: error.message
        });
    }
});

// Protected route example
app.get('/api/profile', 
    jwtMiddleware.authenticate(),
    (req, res) => {
        res.json({
            message: 'Profile data',
            user: req.user
        });
    }
);

// Admin-only route example
app.get('/api/admin/users',
    jwtMiddleware.requireAdmin(),
    (req, res) => {
        res.json({
            message: 'Admin users data',
            admin: req.user
        });
    }
);

// Route requiring permissions check
app.post('/api/posts',
    jwtMiddleware.requirePermissions(['write']),
    (req, res) => {
        res.json({
            message: 'Post created successfully',
            user: req.user
        });
    }
);

// Route requiring role check
app.get('/api/reports',
    jwtMiddleware.requireRoles(['premium', 'admin']),
    (req, res) => {
        res.json({
            message: 'Reports data',
            user: req.user
        });
    }
);

// Token refresh endpoint
app.post('/auth/refresh', (req, res) => {
    const { refreshToken } = req.body;
    
    if (!refreshToken) {
        return res.status(401).json({
            error: 'Refresh token required'
        });
    }
    
    const result = jwtMiddleware.verificationService.verifyRefreshToken(refreshToken);
    
    if (!result.success) {
        return res.status(401).json({
            error: 'Invalid refresh token',
            message: result.error.message
        });
    }
    
    // Generate new access token
    const newAccessToken = tokenService.generateToken({
        sub: result.payload.sub
    });
    
    res.json({
        accessToken: newAccessToken,
        expiresIn: 3600
    });
});

// Logout endpoint
app.post('/auth/logout', 
    jwtMiddleware.authenticate(),
    (req, res) => {
        // Clear cookie
        res.clearCookie('auth_token');
        
        res.json({
            message: 'Logout successful'
        });
    }
);

async function authenticateUser(username, password) {
    // Actual authentication logic (database, LDAP, etc.)
    // Dummy implementation here
    if (username === 'admin' && password === 'password') {
        return {
            id: '1',
            username: 'admin',
            email: '[email protected]',
            roles: ['admin', 'user'],
            permissions: ['read', 'write', 'delete']
        };
    }
    return null;
}

module.exports = { JWTMiddleware, app };

Asymmetric Encryption (RS256) and Security Enhancement

// RSAJWTService.js - JWT service using RSA key pairs
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');

class RSAJWTService {
    constructor(options = {}) {
        this.algorithm = 'RS256';
        this.issuer = options.issuer || process.env.JWT_ISSUER;
        this.audience = options.audience || process.env.JWT_AUDIENCE;
        
        // Load RSA key pair
        this.loadKeyPair();
    }
    
    // Load RSA key pair
    loadKeyPair() {
        try {
            // Private and public key paths
            const privateKeyPath = process.env.JWT_PRIVATE_KEY_PATH || path.join(__dirname, 'keys', 'private.pem');
            const publicKeyPath = process.env.JWT_PUBLIC_KEY_PATH || path.join(__dirname, 'keys', 'public.pem');
            
            // Generate key files if they don't exist
            if (!fs.existsSync(privateKeyPath) || !fs.existsSync(publicKeyPath)) {
                this.generateKeyPair();
            }
            
            this.privateKey = fs.readFileSync(privateKeyPath, 'utf8');
            this.publicKey = fs.readFileSync(publicKeyPath, 'utf8');
            
            console.log('RSA key pair loaded successfully');
        } catch (error) {
            console.error('Failed to load RSA key pair:', error.message);
            throw new Error('RSA key pair initialization failed');
        }
    }
    
    // Generate RSA key pair
    generateKeyPair() {
        const keysDir = path.join(__dirname, 'keys');
        
        // Create keys directory if it doesn't exist
        if (!fs.existsSync(keysDir)) {
            fs.mkdirSync(keysDir, { recursive: true });
        }
        
        // Generate 2048-bit RSA key pair
        const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
            modulusLength: 2048,
            publicKeyEncoding: {
                type: 'spki',
                format: 'pem'
            },
            privateKeyEncoding: {
                type: 'pkcs8',
                format: 'pem'
            }
        });
        
        // Save key files
        fs.writeFileSync(path.join(keysDir, 'private.pem'), privateKey);
        fs.writeFileSync(path.join(keysDir, 'public.pem'), publicKey);
        
        console.log('New RSA key pair generated and saved');
    }
    
    // Generate token with RSA signature
    generateToken(payload, options = {}) {
        const defaultOptions = {
            algorithm: this.algorithm,
            expiresIn: '1h',
            issuer: this.issuer,
            audience: this.audience,
            keyid: 'rsa-key-1'  // Key ID (useful for multiple key management)
        };
        
        const finalOptions = { ...defaultOptions, ...options };
        
        try {
            // Sign with RSA private key
            const token = jwt.sign(payload, this.privateKey, finalOptions);
            console.log('RSA JWT token generated successfully');
            return token;
        } catch (error) {
            console.error('RSA JWT token generation failed:', error.message);
            throw new Error('RSA token generation failed');
        }
    }
    
    // Verify token with RSA public key
    verifyToken(token, options = {}) {
        const defaultOptions = {
            algorithms: [this.algorithm],
            issuer: this.issuer,
            audience: this.audience,
            clockTolerance: 30
        };
        
        const finalOptions = { ...defaultOptions, ...options };
        
        try {
            // Verify with RSA public key
            const decoded = jwt.verify(token, this.publicKey, finalOptions);
            console.log('RSA JWT token verified successfully');
            return {
                success: true,
                payload: decoded,
                error: null
            };
        } catch (error) {
            console.error('RSA JWT token verification failed:', error.message);
            return {
                success: false,
                payload: null,
                error: this.categorizeError(error)
            };
        }
    }
    
    // Get public key information for JWKS endpoint
    getPublicKeyJWKS() {
        const keyObject = crypto.createPublicKey(this.publicKey);
        const jwk = keyObject.export({ format: 'jwk' });
        
        return {
            keys: [{
                kty: jwk.kty,
                use: 'sig',
                kid: 'rsa-key-1',
                alg: 'RS256',
                n: jwk.n,
                e: jwk.e
            }]
        };
    }
    
    // Advanced token generation (with custom headers)
    generateAdvancedToken(payload, customHeaders = {}) {
        const headers = {
            typ: 'JWT',
            alg: this.algorithm,
            kid: 'rsa-key-1',
            ...customHeaders
        };
        
        const token = jwt.sign(payload, this.privateKey, {
            algorithm: this.algorithm,
            expiresIn: '1h',
            issuer: this.issuer,
            audience: this.audience,
            header: headers
        });
        
        return token;
    }
    
    // Key rotation support
    rotateKeys() {
        try {
            // Backup current keys
            const backupDir = path.join(__dirname, 'keys', 'backup');
            if (!fs.existsSync(backupDir)) {
                fs.mkdirSync(backupDir, { recursive: true });
            }
            
            const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
            fs.copyFileSync(
                path.join(__dirname, 'keys', 'private.pem'),
                path.join(backupDir, `private-${timestamp}.pem`)
            );
            fs.copyFileSync(
                path.join(__dirname, 'keys', 'public.pem'),
                path.join(backupDir, `public-${timestamp}.pem`)
            );
            
            // Generate new key pair
            this.generateKeyPair();
            this.loadKeyPair();
            
            console.log('Key rotation completed successfully');
            return true;
        } catch (error) {
            console.error('Key rotation failed:', error.message);
            return false;
        }
    }
    
    // Generate security report
    generateSecurityReport(tokens = []) {
        const report = {
            timestamp: new Date().toISOString(),
            algorithm: this.algorithm,
            keyStatus: 'active',
            tokensAnalyzed: tokens.length,
            validTokens: 0,
            expiredTokens: 0,
            invalidTokens: 0,
            securityIssues: []
        };
        
        tokens.forEach(token => {
            const result = this.verifyToken(token);
            if (result.success) {
                report.validTokens++;
                
                // Security check
                const payload = result.payload;
                if (!payload.exp || (payload.exp - payload.iat) > 86400) {
                    report.securityIssues.push('Long-lived token detected');
                }
            } else if (result.error.type === 'EXPIRED') {
                report.expiredTokens++;
            } else {
                report.invalidTokens++;
            }
        });
        
        return report;
    }
    
    categorizeError(error) {
        if (error.name === 'TokenExpiredError') {
            return {
                type: 'EXPIRED',
                message: 'Token has expired',
                expiredAt: error.expiredAt
            };
        } else if (error.name === 'JsonWebTokenError') {
            return {
                type: 'INVALID',
                message: 'Token is invalid',
                details: error.message
            };
        } else if (error.name === 'NotBeforeError') {
            return {
                type: 'NOT_ACTIVE',
                message: 'Token not active',
                date: error.date
            };
        } else {
            return {
                type: 'UNKNOWN',
                message: 'Unknown verification error',
                details: error.message
            };
        }
    }
}

// Usage examples and Express.js integration
const express = require('express');
const app = express();

const rsaJWTService = new RSAJWTService({
    issuer: 'secure-app',
    audience: 'secure-app-users'
});

app.use(express.json());

// JWKS endpoint (public key distribution)
app.get('/.well-known/jwks.json', (req, res) => {
    res.json(rsaJWTService.getPublicKeyJWKS());
});

// RSA signed token generation endpoint
app.post('/auth/rsa-login', (req, res) => {
    const { username, password } = req.body;
    
    // Authentication process (omitted)
    const user = { id: 1, username: 'testuser', roles: ['user'] };
    
    const token = rsaJWTService.generateToken({
        sub: user.id,
        username: user.username,
        roles: user.roles
    });
    
    res.json({
        token,
        algorithm: 'RS256',
        message: 'RSA signed token generated'
    });
});

// RSA verification middleware
const requireRSAAuth = (req, res, next) => {
    const authHeader = req.headers.authorization;
    
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
        return res.status(401).json({ error: 'Token required' });
    }
    
    const token = authHeader.substring(7);
    const result = rsaJWTService.verifyToken(token);
    
    if (!result.success) {
        return res.status(401).json({ 
            error: 'Invalid token',
            details: result.error
        });
    }
    
    req.user = result.payload;
    next();
};

// Protected route
app.get('/api/secure-data', requireRSAAuth, (req, res) => {
    res.json({
        message: 'Secure data accessed with RSA verification',
        user: req.user
    });
});

// Key rotation management endpoint (admin only)
app.post('/admin/rotate-keys', requireRSAAuth, (req, res) => {
    if (!req.user.roles.includes('admin')) {
        return res.status(403).json({ error: 'Admin access required' });
    }
    
    const success = rsaJWTService.rotateKeys();
    
    if (success) {
        res.json({ message: 'Key rotation completed successfully' });
    } else {
        res.status(500).json({ error: 'Key rotation failed' });
    }
});

module.exports = RSAJWTService;