In modern web application architecture, stateless authentication is key. When users log in, instead of storing active sessions in server memory, applications often issue a JSON Web Token (JWT). You can inspect and decode token claims locally with our free JWT Decoder Tool or format JSON payloads using our JSON Formatter.
While JWTs are incredibly powerful and standard, they are frequently misunderstood. Developers often confuse encoded tokens with encrypted tokens, exposing sensitive user information. Additionally, debugging token payloads online poses security risks when using server-side formatters.
In this guide, we will break down the structural mechanics of JWTs, explore the critical differences between signing and encryption, highlight standard security pitfalls, and provide a secure, 100% client-side interactive JWT debugger.
The Three Components of a JWT
A JSON Web Token is a compact, URL-safe string representation of claims. It is comprised of three distinct parts separated by dots (.):
$$\text{JWT} = \color{#f87171}{\text{Header}} \cdot \color{#c084fc}{\text{Payload}} \cdot \color{#4ade80}{\text{Signature}}$$
Let’s analyze what each part does:
1. The Header (Red)
The Header contains metadata about the token. Usually, it consists of two fields:
alg: The hashing algorithm used (such asHS256for HMAC-SHA256 orRS256for RSA).typ: The type of token, which is almost always"JWT".
Example Header JSON:
{
"alg": "HS256",
"typ": "JWT"
}
2. The Payload (Purple)
The Payload contains the actual “claims” (attributes) about the user or session. These are divided into:
- Registered Claims: Standardized, pre-defined claims like
sub(subject/user ID),iat(issued at time), andexp(expiration timestamp). - Public Claims: Custom claims meant for sharing information across applications.
- Private Claims: Custom claims shared between the specific provider and consumer of the token.
Example Payload JSON:
{
"sub": "1234567890",
"name": "Jane Doe",
"role": "administrator",
"iat": 1774886400,
"exp": 1806422400
}
3. The Signature (Green)
The Signature is used to verify that the token wasn’t tampered with along the way. To create the signature, the Base64URL-encoded header and payload are combined, concatenated with a secret (in symmetric algorithms like HS256) or a private key (in asymmetric algorithms like RS256), and signed using the hashing algorithm.
For example, using HMAC-SHA256:
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
Critical Security Risks & Best Practices
When integrating JWTs in your frontend or backend, keep the following security guidelines in mind:
1. Base64 is NOT Encryption
A standard JWT is signed, not encrypted. Base64URL encoding is a reversible encoding scheme, not an encryption technique. Anyone who intercepts the token can read your payload in plain text.
- Rule: Never place highly sensitive data (like passwords, API keys, or credit card numbers) in a standard JWT payload. If you must send sensitive data inside a token, use JWE (JSON Web Encryption) instead.
2. Avoid the none Hashing Algorithm
Early JWT specifications supported a hashing algorithm called "none". This allowed clients to send unsigned tokens with headers like {"alg": "none"}. Insecure backend validators that trusted this header would skip signature validation entirely, allowing attackers to forge arbitrary payloads (e.g., setting their user role to "admin").
- Rule: Ensure your backend token validator explicitly rejects tokens signed with the
"none"algorithm.
3. Choose the Right Storage
- Local Storage / Session Storage: Susceptible to Cross-Site Scripting (XSS) attacks. If an attacker injects a malicious script, they can query your localStorage and steal the JWT.
- HttpOnly / Secure Cookies: Shielded from client-side JavaScript, mitigating XSS theft. However, cookies are vulnerable to Cross-Site Request Forgery (CSRF). Combine them with proper CSRF protection measures (e.g., SameSite attributes).
Interactive Demo: Secure JWT Decoder
Try debugging a JWT locally in the widget below. This tool processes your token entirely inside your browser runtime. No network requests are sent, ensuring your tokens remain secure and confidential.