JWT Decoder: Decode, Debug & Verify JSON Web Tokens
Technical Mastery Overview
What Is a JSON Web Token?
A JSON Web Token is a compact, URL-safe string used to transmit claims between two parties. You'll encounter JWTs as the value of Authorization: Bearer <token> headers, inside cookies, or embedded in OAuth callback URLs. They're produced by identity providers (Auth0, Cognito, Firebase Auth, Keycloak) and consumed by your API to verify who the caller is and what they're allowed to do.
A raw JWT looks like this:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsIm5hbWUiOiJKYW5lIERvZSIsImlhdCI6MTcwOTI5NjAwMCwiZXhwIjoxNzA5MzgyNDAwLCJyb2xlIjoiYWRtaW4ifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Three Base64URL-encoded segments separated by dots. The dots are load-bearing — strip one and the token is instantly invalid.
The Three-Part Structure
Header — the first segment — decodes to:
{
"alg": "RS256",
"typ": "JWT"
}
alg tells the receiver which signing algorithm was used. RS256 means the token was signed with a private RSA key and can be verified with the corresponding public key. HS256 means a shared secret was used for HMAC-SHA256. The algorithm matters enormously for security — more on that below.
Payload — the second segment — decodes to the claims:
{
"sub": "user_123",
"name": "Jane Doe",
"iat": 1709296000,
"exp": 1709382400,
"role": "admin",
"iss": "https://auth.example.com",
"aud": "https://api.example.com"
}
Signature — the third segment — is the cryptographic proof. You cannot decode a valid signature without the key; you can only verify it. Our JWT Debugger decodes the header and payload (which are just Base64URL, not encrypted) and makes claims readable — but it correctly does not claim to verify signatures without a key.
Registered Claims You Must Know
The JWT spec (RFC 7519) reserves a set of claim names. These aren't enforced by the format itself — they're conventions your application must check:
| Claim | Full name | What it means |
|---|---|---|
sub |
Subject | Unique identifier for the user (user ID, UUID) |
iss |
Issuer | Who created the token (your auth server URL) |
aud |
Audience | Who the token is intended for (your API URL) |
exp |
Expiration | Unix timestamp after which the token is invalid |
iat |
Issued at | Unix timestamp of when the token was created |
nbf |
Not before | Token is invalid before this timestamp |
jti |
JWT ID | Unique token ID, used for revocation lists |
When you paste a token into our debugger, all Unix timestamps are converted to your local timezone automatically — you can see at a glance whether a session has expired, without running date -d @1709382400 in a terminal.
JWT vs. Session Tokens: When to Use Each
A common architectural question. Here's how they compare:
| JWT (stateless) | Server sessions (stateful) | |
|---|---|---|
| Storage | Client-side (cookie or localStorage) | Server-side (Redis, DB) |
| Revocation | Hard — token valid until exp |
Instant — delete the session |
| Scalability | Excellent — any server validates | Requires shared session store |
| Payload size | Grows with claims | Fixed (session ID only) |
| Offline use | Yes | No |
| Best for | Microservices, APIs, mobile | Traditional web apps, admin tools |
The key tradeoff: JWTs cannot be revoked mid-flight unless you maintain a token blocklist — which reintroduces statefulness. If you need instant logout (financial apps, security-sensitive admin panels), either use short expiry + refresh tokens or stick with server sessions.
Common Debugging Scenarios
1. "401 Unauthorized" errors
The most common cause is an expired exp claim. Paste the token into the debugger, check the expiry timestamp. If it's in the past, your client-side token refresh logic has a bug or the user needs to re-authenticate.
2. "Invalid audience" errors
Your API is validating the aud claim and the token was issued for a different audience. Check that your auth server is including the correct API URL in the audience, and that your middleware is checking against the right value.
3. Missing role or permission claims
Authorization middleware that checks role: "admin" or scopes will silently fail if the claim isn't present. Decode the token to confirm the claim exists and is spelled correctly — roles vs role vs scope vs permissions are all different keys.
4. Clock skew issues
iat or nbf in the future? Your auth server's clock may be ahead of your API server's clock. JWT libraries typically allow a few seconds of skew. If you're seeing consistent nbf validation failures, check NTP sync on your servers.
Use our Timestamp Converter to translate any Unix timestamp in a claim to a human-readable datetime for cross-referencing with your logs.
The alg: none Vulnerability
One of the most critical JWT security vulnerabilities: some libraries historically accepted "alg": "none" in the header, bypassing signature verification entirely. An attacker could craft a token with arbitrary claims, set the algorithm to none, strip the signature, and gain unauthorized access.
The fix: always specify an explicit allowlist of accepted algorithms in your JWT library configuration. Never accept none. Use RS256 or ES256 (asymmetric) for multi-service architectures, and HS256 (symmetric) only when all consumers share the secret securely.
// Correct — explicit algorithm allowlist
jwt.verify(token, publicKey, { algorithms: ['RS256'] });
// Dangerous — algorithm from token header is trusted implicitly
jwt.verify(token, publicKey); // some older libraries had this bug
Signing Algorithm Selection Guide
| Algorithm | Type | Key material | Use when |
|---|---|---|---|
HS256 |
Symmetric (HMAC) | Shared secret | Single service, secret stays internal |
HS512 |
Symmetric (HMAC) | Shared secret | Same as HS256 but stronger hash |
RS256 |
Asymmetric (RSA) | Private + public key | Multiple services, public key distributed |
ES256 |
Asymmetric (ECDSA) | Private + public key | Same as RS256 but smaller tokens |
RS512 |
Asymmetric (RSA) | Private + public key | Higher security requirement |
For generating the secrets used in HS256 signing, use our Password Generator with 32+ characters and full character set — the entropy of your secret is your security ceiling.
Refresh Tokens and Short-Lived Access Tokens
Best practice is to issue short-lived access tokens (15 minutes) paired with long-lived refresh tokens (7–30 days). The access token goes in the Authorization header; the refresh token is stored in an HttpOnly cookie. When the access token expires, the client silently exchanges the refresh token for a new pair.
This pattern limits the blast radius of a stolen token while keeping the user experience smooth. Decode your access token's exp to confirm your token lifetimes are configured correctly — many teams discover their tokens are set to 24 hours or 7 days with no refresh mechanism, which is both a security and UX problem.
Security: Why Local Decoding Matters
Many online JWT decoders send your token to their servers. This is a critical mistake — JWTs often contain sensitive user identifiers, role assignments, and in poorly designed systems, actual PII. A compromised decoder server can harvest tokens that are still valid.
Our debugger processes everything on your CPU. The decoding logic is JavaScript running in your browser tab. Nothing is transmitted. This local-first architecture means you can safely paste production tokens from your staging environment or debugging sessions.
If you need to share a token structure with a colleague, strip the signature first and redact the sub and any PII claims — or use our PII Redactor to sanitize the payload before sharing.
Inspecting JWKS Endpoints
In RS256 setups, the public key used for signature verification is published at a JWKS (JSON Web Key Set) endpoint — usually /.well-known/jwks.json on your auth server. The kid (key ID) claim in the JWT header tells the verifier which key to use from the set.
If you're debugging an invalid signature error with RS256, check:
- Does the
kidin the token header match a key ID in the JWKS endpoint? - Is the
issclaim pointing to the correct auth server? - Has the signing key been rotated without updating your cached public key?
Verification vs. Decoding
Decoding a JWT is not the same as verifying it. Anyone can decode a JWT — it's just Base64URL encoding, not encryption. The payload claims are not secret; they're simply not tamper-proof without the signature check. Verification requires the public or private key used by the issuer and is what your backend middleware performs on every request.
Use the debugger to inspect content and understand structure. Use your backend JWT library (jsonwebtoken, python-jose, golang-jwt) to perform cryptographic verification in production.
Workflow Integration
Pair the JWT Debugger with:
- Timestamp Converter — translate
iat,exp,nbfto readable datetimes - Hash Generator — generate or verify HMAC signatures for HS256 debugging
- PII Redactor — sanitize token payloads before sharing in tickets or logs
- Webhook Signature Verifier — validate HMAC-signed webhook events in the same auth stack
- Base64 Decoder — manually decode individual segments to inspect raw bytes
Experience it now.
Use the professional-grade JWT Debugger with zero latency and 100% privacy in your browser.