JWT Security: JSON Web Token Attacks and Best Practices
Learn about JSON Web Token security including common vulnerabilities like algorithm confusion, key leakage, and implementation flaws with defense strategies.
When a Token Becomes a Backdoor
A server issues a JWT that says {"user": "admin", "role": "user"}. The attacker decodes it (the payload is just base64, not encrypted), changes "role": "user" to "role": "admin", re-encodes it, and sends it back. If the server does not verify the signature properly — or uses the "none" algorithm — the attacker just escalated to admin. JWT security is about making sure tokens cannot be forged, tampered with, or replayed.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Prerequisites
Before studying JWT security, you should understand:
JWT Structure
Header
{
"alg": "HS256",
"typ": "JWT"
}
Payload
{
"sub": "user123",
"name": "John Doe",
"role": "admin",
"iat": 1516239022,
"exp": 1516242622,
"iss": "https://auth.example.com",
"aud": "https://api.example.com"
}
Signature
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
Common JWT Attacks
Algorithm Confusion Attack
The most critical JWT vulnerability. When the server uses asymmetric algorithms (RS256) to verify tokens but the library accepts the algorithm from the token header, an attacker can change the algorithm to HS256 and sign with the public key:
import jwt
# Vulnerable — accepts algorithm from token
def verify_token_vulnerable(token):
payload = jwt.decode(token, options={"verify_exp": True})
return payload
Attack: Get the server's public key (often at /.well-known/jwks.json), create a token with alg: "HS256", sign using the public key as the HMAC secret.
Weak or Exposed Secret
# Crack JWT secret with hashcat
hashcat -m 16500 jwt.txt /usr/share/wordlists/rockyou.txt
# Use jwt_tool for analysis
python jwt_tool.py eyJhbGciOiJIUzI1NiJ9... -C -d /usr/share/wordlists/rockyou.txt
None Algorithm Attack
Setting the algorithm to "none" to bypass signature verification:
{
"alg": "none",
"typ": "JWT"
}
JWK Injection
The token contains an embedded public key (jwk header) that the server uses for verification. An attacker generates their own key pair, embeds the public key, and signs with their private key.
Secure JWT Implementation
Proper Algorithm Validation
import jwt
def verify_token_secure(token):
try:
payload = jwt.decode(
token,
public_key,
algorithms=["RS256"],
audience=["https://api.example.com"],
issuer="https://auth.example.com",
options={
"verify_exp": True,
"verify_iat": True,
"verify_aud": True
}
)
return payload
except jwt.InvalidTokenError as e:
raise AuthenticationError(f"Invalid token: {e}")
Use Asymmetric Algorithms
# Generate RSA key pair
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -pubout -out public.pem
Token Creation
import jwt
from datetime import datetime, timedelta
def create_access_token(user_id, role):
payload = {
"sub": user_id,
"role": role,
"iat": datetime.utcnow(),
"exp": datetime.utcnow() + timedelta(hours=1),
"iss": "https://auth.example.com",
"aud": "https://api.example.com",
"jti": str(uuid.uuid4())
}
token = jwt.encode(payload, private_key, algorithm="RS256")
return token
Token Revocation
Since JWTs are stateless, implement a denylist:
import redis
redis_client = redis.Redis()
def revoke_token(jti, expires_in):
redis_client.setex(f"revoked:{jti}", expires_in, "1")
def is_token_revoked(jti):
return redis_client.exists(f"revoked:{jti}")
Real-World Examples
Auth0 JWT Vulnerability (2020): A critical vulnerability in multiple JWT libraries allowed the none algorithm attack even when explicitly disabled.
CVE-2022-23529 (jsonwebtoken): Remote code execution in the popular jsonwebtoken npm library allowed attackers to execute code through crafted JWTs.
Microsoft Azure AD (2021): Tokens signed with a misconfigured Azure AD tenant could be used to access resources in other tenants.
Common Mistakes
Not validating the algorithm: Enables algorithm confusion attacks.
Using weak secrets: Dictionary words for HMAC secrets can be cracked with hashcat.
Not validating expiration: Tokens that never expire increase leak damage.
No audience or issuer validation: Tokens from any issuer are accepted.
Long token lifetimes: Access tokens valid for weeks increase the attack window.
Best Practices
Related Tools
Related Articles
Summary
JWT has several critical security pitfalls. The most dangerous is the algorithm confusion attack. Defenses include explicit algorithm validation, short token lifetimes, proper claim verification, and using asymmetric signing algorithms.