Understanding JSON Web Tokens (JWT): Structure, Security Vulnerabilities, and Debugging Guide
Master JSON Web Tokens (JWT) in modern authentication. Learn the anatomy of Headers, Payloads, and Signatures (HMAC vs RSA/ECDSA), prevent security pitfalls like algorithm confusion, and debug tokens in real-time.
In modern stateless web architectures, microservices, and Single-Page Applications (SPAs), JSON Web Tokens (JWTs) have become the industry standard for transmitting verifiable identity claims between parties. Whether authenticating API requests via OAuth 2.0 / OpenID Connect, managing session state across serverless functions, or passing user authorization scopes, JWTs are everywhere.
However, despite their ubiquity, JWTs are frequently misunderstood and misconfigured. Developers often confuse encoding with encryption, inadvertently leak sensitive data in payloads, or introduce critical authentication vulnerabilities such as the none algorithm exploit and key confusion attacks.
In this educational tutorial, you will learn the exact internal anatomy of a JWT (RFC 7519), understand symmetric vs. asymmetric cryptographic signatures, review defensive best practices, and debug your tokens using interactive browser-based developer tools.
π‘ Key Takeaways (TL;DR)#
- Three-Part Structure: A JWT is a Base64URL-encoded string consisting of three parts separated by dots:
Header.Payload.Signature. - Encoded, Not Encrypted: By default, standard JWTs are signed, not encrypted (JWS). Anyone with access to the token string can decode and read the JSON payload. Never store raw passwords, API keys, or sensitive PII in a payload.
- Symmetric vs. Asymmetric Signing: HS256 uses a shared symmetric secret (
HMAC-SHA256). RS256/ES256 uses a private key for signing and a public key for verification, making it ideal for microservice architectures. - Critical Security Gotchas: Always enforce allowed algorithms on your backend to prevent
alg: "none"bypasses, set strictexp(expiration) timestamps, and store tokens in secureHttpOnly; SameSite=Strictcookies. - Interactive Debugging: Inspect token headers, claims, and signature validity directly in your browser using the JWT Debugger.
1. Anatomy of a JSON Web Token#
A JSON Web Token is a compact, URL-safe string containing three distinct segments separated by periods (.):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvZXkiLCJpYXQiOjE1MTYyMzkwMjJ9.4zU_...
βββββββββββββββ Header βββββββββββββββ.βββββββββββββββ Payload βββββββββββββββ.ββββββββββ Signature ββββββββββ
Segment 1: The Header#
The header specifies the token type and the cryptographic algorithm used to generate the signature:
{
"alg": "HS256",
"typ": "JWT"
}
Segment 2: The Payload (Claims)#
The payload contains the claimsβstatements about an entity (typically the user) and additional metadata. Claims fall into three categories:
- Registered Claims (Predefined):
sub(Subject): Unique user ID (e.g.usr_90210).iss(Issuer): The identity provider issuing the token (e.g.https://auth.joeyjazwinski.com).exp(Expiration Time): Unix timestamp when the token becomes invalid.iat(Issued At): Unix timestamp when the token was created.
- Public Claims: Standardized custom names defined in the IANA JSON Web Token Registry.
- Private Claims: Custom application-specific properties (e.g.
role: "admin",tenantId: "org_42").
{
"sub": "usr_90210",
"name": "Joey Jazwinski",
"role": "admin",
"iat": 1773489600,
"exp": 1773493200
}
Segment 3: The Signature#
The signature prevents tampering. It is computed by taking the Base64URL-encoded header, Base64URL-encoded payload, and hashing them with a secret key:
Signature = HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
SECRET_KEY
)
2. Interactive Tool: Inspect & Verify Tokens in Real-Time#
π οΈ Live Developer Tool Callout#
Need to quickly decode a token payload, inspect standard claims, or verify HMAC/RSA signatures?
- Decode & Verify Tokens Instantly: Use the free, client-side JWT Debugger to test token expiration, parse payload claims, and validate signatures securely in your browser without sending tokens over the network.
- Convert Keys for Asymmetric Signatures: Need to generate public verification keys? Use the PEM to JWK Converter.
- Explore More Security Tools: Check out the Hash & HMAC Generator and Password Generator on the Developer Tools Hub.
3. Cryptographic Signing: HS256 vs. RS256#
Understanding the difference between symmetric and asymmetric signing is crucial for secure distributed systems:
Symmetric vs. Asymmetric Comparison#
| Feature | HS256 (HMAC-SHA256) | RS256 / ES256 (RSA / ECDSA) |
|---|---|---|
| Key Type | Single Shared Secret | Private Key (Sign) + Public Key (Verify) |
| Performance | Extremely Fast (Minimal CPU overhead) | Slightly slower (Higher cryptographic computation) |
| Security Risk | If one microservice is compromised, attackers can forge tokens | Microservices only receive the public key; cannot forge tokens |
| Best Used For | Monolithic backends, internal private services | Distributed microservices, OAuth2 Identity Providers (IdP) |
4. Common JWT Security Vulnerabilities & How to Prevent Them#
1. The alg: "none" Algorithm Exploit#
In flawed JWT verification libraries, an attacker can modify the token header to {"alg": "none"}, strip the signature, and submit arbitrarily modified payload claims (e.g. elevating role: "user" to role: "admin"). If the backend blindly trusts the header algorithm, it validates the token without a signature!
Defense: Never trust the algorithm declared in the header. Explicitly specify expected algorithms in your verification options:
// Backend Verification in Node.js / TypeScript
import jwt from 'jsonwebtoken';
export function verifyUserToken(token: string, publicKey: string) {
return jwt.verify(token, publicKey, {
algorithms: ['RS256'], // Explicitly whitelist allowed algorithms!
});
}
2. Key Confusion Attacks (HMAC vs. RSA)#
When a server supports both RS256 and HS256, an attacker can take the server's public RSA key (which is public knowledge) and use it as a symmetric secret to sign a token with HS256. If the verification function uses the same key variable without checking the algorithm, it validates the forged HMAC signature using the public key string.
Defense: Strictly separate verification pathways for asymmetric and symmetric tokens.
3. Insecure Token Storage (XSS vs. CSRF)#
Where you store your JWT in the browser dictates your vulnerability exposure:
- Avoid
localStorage: Any cross-site scripting (XSS) vulnerability in a third-party npm package can readlocalStorage.getItem('token')and exfiltrate your user sessions. - Use
HttpOnly; Secure; SameSite=StrictCookies: Browsers automatically attach the cookie to API requests, but JavaScript cannot read or extract it.
5. Token Revocation & Refresh Token Pattern#
Because JWTs are stateless, once issued, a token remains valid until its exp timestamp passes. If a user changes their password or reports a compromised account, how do you revoke access?
The standard enterprise pattern utilizes Short-Lived Access Tokens (10β15 minutes) paired with Long-Lived Refresh Tokens (7β30 days) stored in a database:
Frequently Asked Questions#
Can I encrypt a JWT if I need to store sensitive data?#
Yes. If payload confidentiality is required, use JSON Web Encryption (JWE) (RFC 7516), which encrypts payload contents so that only the holder of the decryption key can view the claims.
What is the ideal expiration time for an access token?#
For security-conscious applications, access tokens should expire within 5 to 15 minutes. Long-lived access tokens (hours or days) expand the blast radius if intercepted.
How do I handle clock skew between servers?#
Network servers may have slight clock drift. When verifying exp and iat claims, configure a small tolerance (e.g. clockTolerance: 30 seconds) in your JWT verification library to prevent false rejection of valid tokens.
Joey Jazwinski
Hi, I'm Joey β a software engineer building modern applications, exploring artificial intelligence, and sharing my journey through code. π
Recommended Articles
View all posts βXML Sitemaps Explained: Protocol Standards, Large-Scale Architecture, and Generator Guide
Master XML sitemaps for modern web indexing. Learn sitemap protocol standards, sitemap index splitting rules, image/news extensions, Next.js automation, and generate valid sitemaps with free developer tools.
Building a Custom Hash Map from Scratch: Collision Resolution, Robin Hood Hashing, and Dynamic Rehashing
Build a high-performance hash map from first principles in C and Rust. Explore hash functions (MurmurHash3, FNV-1a), collision resolution strategies (Separate Chaining vs Open Addressing), Robin Hood hashing, load factors, and dynamic resizing.
Demystifying Asymptotic Notation: Big-O, Big-Theta, and Big-Omega with Real Code Benchmarks
Master algorithm analysis beyond textbook definitions. Explore Big-O, Big-Theta, and Big-Omega notations with formal mathematical boundaries, common complexity tiers, and empirical wall-clock benchmarks in Python, Rust, and TypeScript.