JWT Debugger: How to Decode, Verify, and Debug JSON Web Tokens

Tools โ€” views

What Is a JWT?

A JSON Web Token (JWT) is a compact, self-contained token format for securely transmitting information between parties. It's widely used for:

  • Authentication โ€” After login, the server issues a JWT; the client sends it with each request to access protected resources
  • API authorization โ€” Microservices use JWTs to pass identity and permissions without hitting a central auth service
  • Single Sign-On (SSO) โ€” Share authentication state across domains

The Three-Part Structure

A JWT is three Base64Url-encoded sections separated by dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U

  Header           Payload              Signature
^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^^^^^^^^^

1. Header

{
  "alg": "HS256",   // signing algorithm: HS256, RS256, ES256
  "typ": "JWT"
}

2. Payload (Claims)

{
  "sub": "1234567890",        // subject: unique user identifier
  "name": "John Doe",
  "iat": 1516239022,          // issued at (Unix timestamp)
  "exp": 1516242622,          // expiration time
  "iss": "auth.example.com",  // issuer
  "aud": "api.example.com"    // audience
}

3. Signature

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  your-secret-key
)

How to Debug a JWT Online

Use the tool.tl JWT Debugger:

  1. Go to tool.tl/jwt-debugger
  2. Paste your JWT token into the input field
  3. Instantly see the decoded Header and Payload in readable JSON
  4. Enter your secret to verify the signature
Security note: The JWT payload is Base64Url encoded, not encrypted. Anyone who gets a JWT can decode it and read its contents. Never put sensitive data (passwords, payment info) in the payload.

Standard JWT Claims Reference

ClaimFull NamePurpose
subSubjectUnique identifier for the user/entity
issIssuerWho issued the token (e.g., auth.example.com)
audAudienceIntended recipient (e.g., api.example.com)
expExpirationToken expiry (Unix timestamp)
iatIssued AtWhen the token was created
nbfNot BeforeToken not valid before this time
jtiJWT IDUnique token ID (for replay prevention)

Common JWT Security Vulnerabilities

1. Algorithm Confusion (alg=none)

An attacker modifies the header to "alg": "none", removing signature verification. Fix: always validate and whitelist the algorithm server-side; reject none.

2. Weak Secret

HS256 uses a shared secret. Simple secrets like "secret" or "password" can be brute-forced offline. Fix: use a cryptographically random secret of at least 256 bits.

3. Missing Expiration Check

Not validating exp means expired tokens remain valid indefinitely. Fix: always verify exp in every token validation, without exception.

JWT in Code

# Python (PyJWT)
import jwt
token = jwt.encode({'sub': '123', 'exp': 1700000000}, 'my-secret', algorithm='HS256')
data  = jwt.decode(token, 'my-secret', algorithms=['HS256'])

// Node.js (jsonwebtoken)
const jwt = require('jsonwebtoken');
const token = jwt.sign({ sub: '123' }, 'my-secret', { expiresIn: '1h' });
const data  = jwt.verify(token, 'my-secret');

# Go (golang-jwt)
token, _ := jwt.Parse(tokenString, func(t *jwt.Token) (interface{}, error) {
    return []byte("my-secret"), nil
})

Frequently Asked Questions

What's the difference between JWT and session-based auth?

Sessions store state server-side (in memory or a database); the client only holds a session ID. JWTs are stateless โ€” all information lives in the token itself. JWTs scale horizontally without shared session storage, but can't be invalidated without a blacklist or short expiry.

Where should I store a JWT on the client?

localStorage is vulnerable to XSS but immune to CSRF. HttpOnly cookies can't be accessed by JavaScript (XSS-safe) but require CSRF protection. The recommended combination: HttpOnly cookie for the access token + a separate CSRF token in a header.

How do I invalidate a JWT before it expires?

JWTs have no built-in revocation. Common patterns: maintain a token blacklist in Redis (check on every request); use short expiry (15 minutes) with a Refresh Token; rotate a per-user secret version so old tokens fail validation.