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 β
Demystifying MongoDB Connection Strings: URI Parameters, Replica Sets, and TLS
A complete engineering guide to MongoDB connection URIs. Learn DNS SRV lookups, replica set topology discovery, write concerns, pool sizing, and TLS options.

How QR Codes Work Under the Hood: Reed-Solomon Error Correction, Mask Patterns, and Matrix Encodings
Explore the computer science and math behind Quick Response codes. Learn 1:1:3:1:1 finder patterns, Galois field error correction, mask formulas, and URI schemes.

Runtime Type Validation in TypeScript: Zod Architecture, Static Type Inference, and API Boundary Defense
Master runtime validation in TypeScript. Learn how Zod executes schema parsing, derives static types with z.infer, and protects API boundaries against invalid input.