JWT Decoder Guide: Read JSON Web Tokens and Debug Auth Issues
If you have worked with any modern API that uses OAuth, OpenID Connect, or token-based authentication, you have almost certainly encountered a JWT. These tokens look like a long, intimidating string of random characters — but they are actually structured data you can read directly. Understanding how to decode a JWT is an essential skill for debugging authentication problems.
This guide explains the structure of a JWT, what is in each part, the critical difference between decoding and verifying, and the security mistakes to avoid.
What Is a JWT?
JWT stands for JSON Web Token. It is an open standard (RFC 7519) for securely transmitting information between parties as a compact, URL-safe string. JWTs are widely used for:
- Authentication: After a user logs in, the server issues a JWT. The client sends this token with every subsequent request to prove identity.
- Authorization: The token contains claims about what the user is allowed to do, so the server can make access decisions without querying a database.
- Information exchange: JWTs can carry verified data between services in a microservices architecture.
The Three-Part Structure
A JWT consists of three base64url-encoded parts separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 .eyJzdWIiOiJ1c2VyXzEyMyIsIm5hbWUiOiJBbGljZSIsImlhdCI6MTcxMDAwMDAwMCwiZXhwIjoxNzEwMDg2NDAwfQ .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
The three parts are:
- Header — specifies the token type and signing algorithm
- Payload — contains the claims (the actual data)
- Signature — verifies the token has not been tampered with
Decoded: What Each Part Contains
The Header
Base64url-decoding the first part of the example token gives:
{
"alg": "HS256",
"typ": "JWT"
}
alg specifies the signing algorithm (HMAC-SHA256 in this case). typ identifies the token type. Common algorithm values include HS256, RS256 (RSA with SHA-256), and ES256 (ECDSA).
The Payload
Base64url-decoding the second part gives the claims:
{
"sub": "user_123",
"name": "Alice",
"iat": 1710000000,
"exp": 1710086400
}
This is where the useful information lives — the user's identity, permissions, and timing constraints.
The Signature
The third part is a cryptographic signature computed over the header and payload using the algorithm and secret key specified in the header. You cannot meaningfully "decode" the signature — its purpose is to be verified, not read.
Standard JWT Claims
| Claim | Name | Description |
|---|---|---|
iss | Issuer | Who issued the token (e.g., https://auth.example.com) |
sub | Subject | Who the token is about (usually a user ID) |
aud | Audience | Who the token is intended for (e.g., your API) |
exp | Expiration | Unix timestamp when the token expires |
iat | Issued At | Unix timestamp when the token was issued |
nbf | Not Before | Token is not valid before this Unix timestamp |
jti | JWT ID | Unique identifier for this token (for revocation) |
Applications also add their own custom claims. You might see email, roles, permissions, tenant_id, or any other application-specific data that needs to travel with the token.
Decode a JWT Instantly
Paste any JWT and see the decoded header and payload in human-readable format — free, no login required.
Open JWT Decoder ToolDecoding vs. Verifying: A Critical Distinction
This is the most important concept to understand when working with JWTs.
Decoding means base64url-decoding the header and payload to read their contents. Anyone can do this — no secret is required. The JWT decoder tool does exactly this.
Verifying means checking the signature to confirm the token was issued by a trusted party and has not been modified. Verification requires the secret key (for HMAC algorithms) or the public key (for RSA/ECDSA algorithms). Without verification, you cannot trust the claims in the token.
A decoder tool is useful for reading and debugging — seeing what claims are present, checking expiry times, understanding the token structure. It does not and cannot tell you whether a token is authentic. Never use an unverified JWT to make authorization decisions in your application.
How to Check if a JWT Is Expired
The exp claim is a Unix timestamp — the number of seconds since January 1, 1970 UTC. To check if a token is expired:
- Decode the payload and find the
expvalue - Compare it to the current Unix timestamp
- If
expis less than the current time, the token is expired
You can quickly check the current Unix timestamp with Math.floor(Date.now() / 1000) in JavaScript or import time; int(time.time()) in Python. The JWT decoder tool typically converts the timestamp to a human-readable date automatically.
How to Decode a JWT Manually
JWT parts are encoded with base64url encoding, which uses - instead of + and _ instead of / compared to standard base64, and omits padding characters. To decode manually in JavaScript:
function decodeJwtPayload(token) {
const parts = token.split('.');
const payload = parts[1];
// Replace base64url chars with standard base64
const base64 = payload.replace(/-/g, '+').replace(/_/g, '/');
// Pad to multiple of 4 if needed
const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, '=');
return JSON.parse(atob(padded));
}
This is exactly what the decoder tool does — base64url-decodes the header and payload and formats them as JSON.
Security Warning: JWT Payload Is Not Encrypted
This is the most commonly misunderstood aspect of JWTs. The payload is only base64url encoded — not encrypted. Base64 encoding is completely reversible by anyone. Any data in a JWT payload can be read by anyone who has the token.
This means you should never put sensitive data in a JWT payload:
- Do not include passwords or password hashes
- Do not include API keys or secrets
- Do not include full credit card numbers or government IDs
- Do not include data the user should not be able to see
JWTs are safe for user identifiers, roles, permissions, email addresses, and other non-sensitive profile information. If you need to transmit encrypted data in a token, use JWE (JSON Web Encryption) rather than a standard JWT.
JWT vs. Session Tokens
Traditional session-based authentication stores session data on the server. The client holds only a session ID cookie. Every request, the server looks up the session ID to find the associated user data.
JWTs are stateless — all the user information is in the token itself. The server does not need to look anything up; it just verifies the signature. This makes JWTs excellent for distributed systems and APIs used by multiple services. The trade-off is that JWTs cannot be easily revoked before expiry (since there is no server-side state to invalidate), and if a token is stolen, it remains valid until it expires.
Use Cases for the JWT Decoder Tool
- Debugging a "401 Unauthorized" error by checking whether the token is expired or contains the expected claims
- Verifying that your auth provider is issuing tokens with the correct roles or permissions
- Inspecting the
audclaim to confirm the token is issued for the right audience - Checking the
issclaim to confirm the token came from the expected issuer - Understanding the structure of a third-party token during integration work
Summary
A JWT is a three-part token: a header specifying the algorithm, a payload containing claims, and a signature for verification. The payload is base64url-encoded — not encrypted — and can be read by anyone with the token. Never include sensitive data in a JWT payload. Decoding reads the contents; verifying checks the signature using the secret or public key. Use the decoder tool to inspect token claims, check expiry, and debug authentication issues. For making authorization decisions in your application, always verify the signature using a proper JWT library.