Validate JWT Tokens Securely
Expert knowledge resource for validating JSON Web Tokens (JWT) with secure signature verification, algorithm confusion prevention, and comprehensive claim
Why it matters
Ensure the integrity and authenticity of your applications by rigorously validating JSON Web Tokens (JWTs). This asset provides expert-level checks against common vulnerabilities, ensuring only legitimate tokens grant access.
Outcomes
What it gets done
Verify JWT signature using appropriate algorithms and keys.
Validate token expiration, issuer, and audience claims.
Prevent algorithm confusion and other common JWT attacks.
Inspect token structure and identify potential security issues.
Install
Add it to your toolbox
Run in your project directory:
curl -fsSL https://spark.entire.vc/get/vb-jwt-token-validator | bash Overview
JWT Token Validator
Expert knowledge resource covering JWT validation principles, security best practices, and implementation patterns with concrete code examples in JavaScript, Python, and Go. Use when implementing or auditing JWT validation logic, preventing algorithm confusion attacks, or setting up secure token verification with JWKS endpoints.
What it does
This skill provides expert knowledge on JSON Web Token (JWT) validation, security analysis, and implementation. It covers JWT structure (header, payload, signature), critical validation steps including signature verification, algorithm validation, expiration checks, issuer verification, audience validation, and not-before checks. The source material includes detailed code examples demonstrating secure validation patterns and common vulnerability mitigations like algorithm confusion attack prevention.
When to use - and when NOT to
Use this skill when implementing authentication systems that rely on JWTs, auditing existing JWT validation code for security vulnerabilities, debugging token expiration or claim validation issues, or setting up JWT validation with JWKS endpoints. It's useful when you need to validate tokens with specific algorithm requirements or when implementing custom claim validation logic.
When NOT to use: Don't use this for generating or signing JWTs (the source material focuses on validation only), and avoid it if you're working with non-JWT token formats like SAML or OAuth opaque tokens.
Inputs and outputs
Inputs: JWT token strings, secret keys or public keys for verification, expected issuer and audience values, JWKS endpoint URLs, algorithm specifications, and custom claim validation requirements.
Outputs: Validation results indicating token validity, decoded payload data when valid, specific error messages for validation failures (expired, invalid signature, algorithm mismatch), security analysis reports identifying vulnerabilities, and validation code examples in JavaScript, Python, or Go.
Integrations
The source material includes implementation examples using:
- jsonwebtoken (Node.js): JavaScript library for JWT verification with explicit algorithm specification and claim validation
- PyJWT (Python): Python library with comprehensive validation options and JWKS support
- jwt-go (Go): Go implementation with RSA signature method validation
- cryptography (Python): For handling key serialization and conversions
- requests (Python): For fetching public keys from JWKS endpoints
Here's a secure JavaScript validation example from the source:
const jwt = require('jsonwebtoken');
function validateToken(token, secret) {
try {
const decoded = jwt.verify(token, secret, {
algorithms: ['HS256'], // Explicitly allow only specific algorithms
issuer: 'your-app.com',
audience: 'api.your-app.com',
clockTolerance: 30 // 30 seconds clock skew tolerance
});
return { valid: true, payload: decoded };
} catch (error) {
return { valid: false, error: error.message };
}
}
Who it's for
Backend developers implementing authentication and authorization systems, security engineers auditing JWT implementations for vulnerabilities, DevOps engineers configuring production token validation, and API developers integrating with OAuth 2.0 or OpenID Connect providers. This skill is useful for developers who need to understand the security implications of different JWT validation approaches beyond basic library usage.
Source README
JWT Token Validator Expert
You are an expert in JSON Web Token (JWT) validation, security analysis, and implementation. You possess deep knowledge of JWT structure, cryptographic algorithms, security vulnerabilities, and best practices for token validation across different programming languages and frameworks.
JWT Structure and Validation Principles
Core Components
- Header: Contains algorithm and token type information
- Payload: Contains claims (registered, public, and private)
- Signature: Cryptographic signature ensuring token integrity
Critical Validation Steps
- Signature Verification: Always verify using the correct algorithm and secret/public key
- Algorithm Validation: Prevent algorithm confusion attacks (e.g., RS256 vs HS256)
- Expiration Check: Validate
expclaim against current time with clock skew tolerance - Issuer Verification: Validate
issclaim matches expected issuer - Audience Validation: Ensure
audclaim contains expected audience - Not Before Check: Validate
nbfclaim if present
Security Best Practices
Algorithm Security
// SECURE: Explicitly specify allowed algorithms
const jwt = require('jsonwebtoken');
function validateToken(token, secret) {
try {
const decoded = jwt.verify(token, secret, {
algorithms: ['HS256'], // Explicitly allow only specific algorithms
issuer: 'your-app.com',
audience: 'api.your-app.com',
clockTolerance: 30 // 30 seconds clock skew tolerance
});
return { valid: true, payload: decoded };
} catch (error) {
return { valid: false, error: error.message };
}
}
// INSECURE: Don't do this - vulnerable to algorithm confusion
// jwt.verify(token, secret); // No algorithm specification
Python Implementation with Comprehensive Validation
import jwt
from datetime import datetime, timezone
import requests
from cryptography.hazmat.primitives import serialization
class JWTValidator:
def __init__(self, issuer, audience, jwks_url=None):
self.issuer = issuer
self.audience = audience
self.jwks_url = jwks_url
self.public_keys = {}
def get_public_key(self, kid):
"""Fetch public key from JWKS endpoint"""
if kid in self.public_keys:
return self.public_keys[kid]
if self.jwks_url:
response = requests.get(self.jwks_url)
jwks = response.json()
for key in jwks['keys']:
if key['kid'] == kid:
# Convert JWK to PEM format
public_key = jwt.algorithms.RSAAlgorithm.from_jwk(key)
self.public_keys[kid] = public_key
return public_key
raise ValueError(f"Public key not found for kid: {kid}")
def validate_token(self, token):
try:
# Decode header to get algorithm and key ID
header = jwt.get_unverified_header(token)
# Security check: Ensure algorithm is acceptable
allowed_algorithms = ['RS256', 'RS384', 'RS512']
if header.get('alg') not in allowed_algorithms:
return {'valid': False, 'error': 'Invalid algorithm'}
# Get public key for verification
public_key = self.get_public_key(header.get('kid'))
# Comprehensive token validation
payload = jwt.decode(
token,
public_key,
algorithms=[header.get('alg')],
issuer=self.issuer,
audience=self.audience,
options={
'verify_signature': True,
'verify_exp': True,
'verify_nbf': True,
'verify_iat': True,
'verify_aud': True,
'verify_iss': True,
'require_exp': True,
'require_iat': True
}
)
# Additional custom validations
if not self.validate_custom_claims(payload):
return {'valid': False, 'error': 'Custom claim validation failed'}
return {'valid': True, 'payload': payload}
except jwt.ExpiredSignatureError:
return {'valid': False, 'error': 'Token has expired'}
except jwt.InvalidTokenError as e:
return {'valid': False, 'error': str(e)}
def validate_custom_claims(self, payload):
"""Implement custom business logic validation"""
# Example: Check if user is active
if payload.get('status') == 'inactive':
return False
# Example: Validate scope claims
required_scopes = {'read', 'write'}
token_scopes = set(payload.get('scope', '').split())
if not required_scopes.issubset(token_scopes):
return False
return True
Common Vulnerabilities and Mitigations
Algorithm Confusion Attack Prevention
// Go implementation with secure algorithm validation
package main
import (
"errors"
"github.com/dgrijalva/jwt-go"
)
func ValidateJWT(tokenString string, publicKey interface{}) (*jwt.Token, error) {
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
// Critical: Validate the algorithm
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, errors.New("unexpected signing method")
}
// Ensure it's specifically RS256
if token.Method.Alg() != "RS256" {
return nil, errors.New("invalid algorithm")
}
return publicKey, nil
})
if err != nil {
return nil, err
}
// Validate standard claims
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
if !claims.VerifyIssuer("expected-issuer", true) {
return nil, errors.New("invalid issuer")
}
if !claims.VerifyAudience("expected-audience", true) {
return nil, errors.New("invalid audience")
}
}
return token, nil
}
Token Inspection and Debugging
Safe Token Decoding (Without Verification)
function inspectToken(token) {
try {
// Decode without verification for inspection
const decoded = jwt.decode(token, { complete: true });
const analysis = {
header: decoded.header,
payload: decoded.payload,
issues: [],
recommendations: []
};
// Security analysis
if (decoded.header.alg === 'none') {
analysis.issues.push('CRITICAL: Algorithm "none" is not secure');
}
if (decoded.header.alg === 'HS256' && !decoded.header.typ) {
analysis.recommendations.push('Consider adding "typ": "JWT" to header');
}
// Expiration analysis
if (decoded.payload.exp) {
const expDate = new Date(decoded.payload.exp * 1000);
const now = new Date();
if (expDate < now) {
analysis.issues.push(`Token expired on ${expDate.toISOString()}`);
} else {
const timeToExpiry = expDate - now;
analysis.recommendations.push(`Token expires in ${Math.round(timeToExpiry / 1000 / 60)} minutes`);
}
} else {
analysis.issues.push('No expiration claim found');
}
return analysis;
} catch (error) {
return { error: 'Invalid token format', details: error.message };
}
}
Production Configuration Examples
Environment-Specific Validation Settings
# JWT validation configuration
jwt:
validation:
algorithms:
- RS256
- RS384
issuer: "https://auth.company.com"
audience:
- "api.company.com"
- "mobile.company.com"
clock_skew_seconds: 30
require_exp: true
require_iat: true
require_nbf: false
jwks:
url: "https://auth.company.com/.well-known/jwks.json"
cache_ttl_seconds: 300
timeout_seconds: 5
custom_validation:
require_scope: true
allowed_token_types: ["access_token"]
max_token_age_hours: 24
Key Recommendations
- Never trust algorithm from token header blindly - always validate against allowed algorithms
- Implement proper key rotation - support multiple valid keys during rotation periods
- Use short expiration times - typically 15 minutes for access tokens
- Validate all relevant claims - don't skip issuer, audience, or expiration checks
- Implement rate limiting - prevent token validation abuse
- Log validation failures - monitor for potential attacks
- Use established libraries - avoid implementing JWT validation from scratch
- Cache public keys securely - but implement proper cache invalidation
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.