Published on December 28, 2024
By EverydayTools Team ·
JSON Web Tokens (JWTs) have become the standard for API authentication and authorization. They're used by major platforms like Google, Microsoft, and countless web applications. Understanding how JWTs work, how to decode them, and how to verify their authenticity is essential for modern web development.
This comprehensive guide will teach you everything about JWT tokens, from their structure to decoding and verification. You'll learn about JWT claims, expiration handling, security considerations, and best practices for working with JWTs in your applications.
Try it instantly: Paste any JWT into the free decoder — see the header, payload, claims, and expiration breakdown in one click.
Open JWT Decoder →Quick Start: Need to decode a JWT right now? Try our free JWT Decoder—it decodes header and payload, shows expiration status, and formats the JSON data for easy reading.
What is a JWT Token?
A JSON Web Token (JWT) is a compact, URL-safe token format used for securely transmitting information between parties. JWTs are self-contained, meaning they carry all necessary information within themselves, making them ideal for stateless authentication.
Key Characteristics of JWTs
- Compact: JWTs are small and can be easily transmitted via URL, POST parameters, or HTTP headers.
- Self-Contained: All necessary information is in the token itself, reducing database lookups.
- Stateless: No server-side session storage required, making them scalable.
- Signed: JWTs are signed to ensure integrity and authenticity.
- Standardized: Based on RFC 7519, ensuring compatibility across platforms.
Common Use Cases
- API Authentication: Authenticate API requests without storing sessions.
- Single Sign-On (SSO): Share authentication across multiple applications.
- Information Exchange: Securely transmit information between parties.
- Authorization: Include user permissions and roles in the token.
- Microservices: Authenticate requests between microservices.
JWT Structure
A JWT consists of three parts separated by dots (.): header.payload.signature
Example JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c1. Header
The header typically consists of two parts: the token type (JWT) and the signing algorithm (e.g., HMAC SHA256 or RSA).
{
"alg": "HS256",
"typ": "JWT"
}2. Payload
The payload contains the claims. Claims are statements about an entity (typically the user) and additional metadata.
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516242622
}3. Signature
The signature is used to verify that the sender of the JWT is who it says it is and to ensure that the message wasn't changed along the way.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)How to Decode a JWT
Decoding a JWT is straightforward—it only requires base64 decoding. However, remember that decoding doesn't verify the signature. Anyone can decode a JWT, but only those with the secret key can verify it.
Using Our JWT Decoder Tool
- Paste Your JWT: Copy and paste your JWT token into the input field. You can include or exclude the "Bearer" prefix.
- Automatic Decoding: The tool automatically decodes the header and payload, displaying them as formatted JSON.
- View Claims: See all claims in the payload, including standard claims like 'exp', 'iat', 'sub', and custom claims.
- Check Expiration: The tool automatically checks if the token is expired and displays expiration status.
- Copy Decoded Data: Copy the decoded header or payload JSON for use in your code or documentation.
Decoding Programmatically
JavaScript:
function decodeJWT(token) {
const parts = token.split('.');
const header = JSON.parse(atob(parts[0]));
const payload = JSON.parse(atob(parts[1]));
return { header, payload };
}Important: Decoding a JWT only reveals its contents—it doesn't verify authenticity. Always verify the signature before trusting JWT data in production applications. If you inspect payload claims manually, validate decoded claim objects in JSON syntax validator first to catch malformed test tokens.
Verifying JWT Signatures
Signature verification ensures that the JWT hasn't been tampered with and was issued by a trusted party. This requires the secret key (for HMAC algorithms) or public key (for RSA algorithms).
Why Verification Matters
- Prevents Tampering: Verifies that the token hasn't been modified after issuance.
- Ensures Authenticity: Confirms the token was issued by a trusted source.
- Protects Data: Prevents attackers from creating fake tokens with modified claims.
- Validates Integrity: Ensures the header and payload match the signature.
Verification Steps
- Extract Header and Payload: Decode the header and payload from the JWT.
- Check Algorithm: Verify the algorithm matches what you expect (prevent algorithm confusion attacks).
- Recreate Signature: Use the secret key and the same algorithm to recreate the signature.
- Compare Signatures: Compare the recreated signature with the signature in the JWT.
- Check Expiration: Verify the token hasn't expired by checking the 'exp' claim.
- Validate Claims: Check other claims like 'iss' (issuer), 'aud' (audience) if applicable.
JWT Anatomy — Visual Breakdown
A JWT token has three base64url-encoded sections separated by dots (.):
Header
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
alg: HS256
typ: JWT
Payload (Claims)
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
sub: 1234567890
name: John Doe
iat: 1516239022
Signature
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
HMAC-SHA256 of
header.payload + secret
JWT Verification — Code Examples
Always verify tokens server-side. Here are copy-paste snippets for the most common runtimes:
NNode.js — jsonwebtoken
const jwt = require('jsonwebtoken');
const SECRET = process.env.JWT_SECRET; // never hardcode secrets
// ✅ Verify and decode in one step
try {
const payload = jwt.verify(token, SECRET, {
algorithms: ['HS256'], // whitelist — prevents alg:none attacks
audience: 'myapp', // optional but recommended
issuer: 'myapp-auth', // optional but recommended
});
console.log('Valid token. User ID:', payload.sub);
} catch (err) {
// err.name: 'TokenExpiredError' | 'JsonWebTokenError'
console.error('Invalid token:', err.message);
}
// ✅ Decode WITHOUT verifying (read-only, don't trust for auth)
const decoded = jwt.decode(token, { complete: true });
console.log('Header:', decoded.header);
console.log('Payload:', decoded.payload);PyPython — PyJWT
import jwt # pip install PyJWT
import os
SECRET = os.environ["JWT_SECRET"] # never hardcode secrets
# ✅ Verify and decode
try:
payload = jwt.decode(
token,
SECRET,
algorithms=["HS256"], # whitelist required
audience="myapp", # optional
issuer="myapp-auth", # optional
)
print("Valid token. User ID:", payload["sub"])
except jwt.ExpiredSignatureError:
print("Token has expired")
except jwt.InvalidTokenError as e:
print("Invalid token:", e)
# ✅ Decode WITHOUT verifying (don't trust for auth)
header = jwt.get_unverified_header(token)
payload = jwt.decode(token, options={"verify_signature": False})
print("Algorithm:", header["alg"])alg:none trick or an RSA/HMAC confusion attack.Understanding JWT Claims
Claims are pieces of information asserted about a subject. JWTs include registered claims, public claims, and private claims.
Registered Claims
- iss (Issuer): Identifies who issued the JWT.
- sub (Subject): Identifies the subject of the JWT (usually the user ID).
- aud (Audience): Identifies the recipients that the JWT is intended for.
- exp (Expiration Time): Unix timestamp when the JWT expires.
- nbf (Not Before): Unix timestamp before which the JWT must not be accepted.
- iat (Issued At): Unix timestamp when the JWT was issued.
- jti (JWT ID): Unique identifier for the JWT.
Custom Claims
You can add custom claims to include any additional information needed for your application, such as user roles, permissions, or preferences.
{
"sub": "1234567890",
"name": "John Doe",
"role": "admin",
"permissions": ["read", "write"],
"exp": 1516242622
}JWT Security Best Practices
- Always Verify Signatures: Never trust a JWT without verifying its signature. Decoding is not verification.
- Use Strong Secrets: Use cryptographically strong, random secrets for HMAC algorithms. Never use weak or predictable secrets.
- Set Short Expiration Times: Use short-lived tokens (15 minutes to 1 hour) and implement refresh tokens for longer sessions.
- Validate All Claims: Check expiration, issuer, audience, and other relevant claims before accepting a token.
- Use HTTPS: Always transmit JWTs over HTTPS to prevent interception and man-in-the-middle attacks.
- Avoid Sensitive Data: Don't store sensitive information like passwords in JWT payloads. JWTs are encoded, not encrypted.
- Prevent Algorithm Confusion: Always specify the expected algorithm when verifying. Don't trust the 'alg' claim blindly.
- Implement Token Revocation: For critical applications, maintain a blacklist of revoked tokens or use short expiration times.
- Store Securely: If storing JWTs client-side, use httpOnly cookies when possible, or secure localStorage with proper security headers.
- Monitor and Log: Log JWT verification failures and monitor for suspicious patterns or attacks.
Security Warning: JWTs are encoded (base64), not encrypted. Anyone can decode a JWT and read its contents. Only the signature prevents tampering. Never store sensitive data in JWTs that shouldn't be visible to clients.
Common JWT Attacks
JWTs are widely used but often misconfigured. Understanding the attack surface helps you avoid critical vulnerabilities.
1. Algorithm Confusion (alg:none / RS256→HS256)
An attacker changes the alg header to none and strips the signature. Vulnerable servers accept these unsigned tokens. Another variant downgrades from RS256 to HS256 and signs with the public key.
Fix: Explicitly whitelist allowed algorithms server-side. Never accept alg:none.
2. Weak Secret / Brute-Force
HMAC-signed JWTs using short or guessable secrets can be cracked offline using tools like Hashcat. An attacker collects a valid token and attempts millions of secrets per second.
Fix: Use a cryptographically random secret of at least 256 bits. Rotate secrets regularly.
3. Missing Expiration (exp)
Tokens without an exp claim remain valid forever. If a token is stolen, the attacker can use it indefinitely.
Fix: Always set exp. Use short lifetimes (15–60 min for access tokens) plus refresh tokens.
4. JWT Header Injection (jwk / jku / kid)
The JWT header can include a jwk (embedded key) or jku (key URL). A vulnerable server fetches and trusts an attacker-controlled key, allowing forged tokens.
Fix: Never use keys from the jwk or jku header. Maintain an allow-list of trusted key IDs.
5. Storing JWT in localStorage
Tokens in localStorage are accessible to any JavaScript on the page. An XSS attack can silently steal them.
Fix: Store access tokens in memory. Use HttpOnly cookies for refresh tokens to prevent XSS access.
Use our JWT Decoder to inspect any token's alg, exp, and header claims — all client-side, nothing uploaded.
Conclusion
JWT tokens are powerful tools for authentication and authorization in modern web applications. Understanding their structure, how to decode them, and how to verify signatures is essential for secure API development.
Remember to always verify signatures, validate claims, use short expiration times, and follow security best practices. With proper implementation, JWTs provide a scalable, stateless solution for authentication.
Ready to decode a JWT? Use our free JWT Decoder to inspect token contents, check expiration, and understand JWT structure. No signup required, completely free, and works instantly in your browser.
Decode JWT Now →Frequently Asked Questions
What is a JWT token?
JWT (JSON Web Token) is a compact, URL-safe token format used for securely transmitting information between parties. It consists of three parts: header, payload, and signature, separated by dots.
How do I decode a JWT token?
Use our free online JWT Decoder tool. Simply paste your JWT token, and the tool will decode the header and payload, showing you the JSON data inside. You can also decode JWTs programmatically using base64 decoding.
What information is in a JWT?
A JWT contains a header (algorithm and token type), payload (claims/data), and signature (for verification). The payload typically includes user information, expiration time, and other claims.
Is decoding a JWT secure?
Decoding a JWT only reveals the header and payload, which are base64-encoded (not encrypted). Anyone can decode a JWT, but only those with the secret key can verify its signature and trust its contents.
What does JWT signature verification do?
Signature verification ensures the JWT hasn't been tampered with. It uses the secret key to verify that the header and payload match the signature. Only tokens with valid signatures should be trusted.
How do I check if a JWT is expired?
Check the 'exp' (expiration) claim in the payload. It's a Unix timestamp. If the current time is greater than the exp value, the token is expired. Our JWT Decoder automatically checks expiration.
What are JWT claims?
Claims are pieces of information in the JWT payload. Standard claims include 'iss' (issuer), 'exp' (expiration), 'sub' (subject), 'iat' (issued at), and 'aud' (audience). You can also add custom claims.
Can I decode a JWT without the secret?
Yes! Decoding only requires base64 decoding, which anyone can do. However, verifying the signature requires the secret key. Always verify signatures before trusting JWT contents.
What's the difference between JWT decode and verify?
Decoding extracts the data from a JWT (anyone can do this). Verifying checks that the signature is valid and the token hasn't been tampered with (requires the secret key).
How do I use JWTs in API authentication?
Include the JWT in the Authorization header as 'Bearer <token>'. The server decodes and verifies the token to authenticate the request. JWTs are stateless, making them ideal for APIs.