DevKit
← Back to Blog

JWT Tokens Explained: Decode, Validate, and Debug Like a Pro

8 min read

JSON Web Tokens (JWTs) are everywhere in modern authentication. Login to almost any SPA and you will find a JWT in your localStorage or cookies. Yet many developers treat them as magic strings — paste them into headers and hope they work.

This guide demystifies JWTs so you can decode, validate, and debug them confidently.

What is a JWT?

A JWT is a compact, URL-safe string that carries claims (data) between parties. It looks like this:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.signature

Three parts separated by dots: Header.Payload.Signature. Each part is Base64URL-encoded JSON (except the signature which is a hash).

The Three Parts

Header

Declares the token type and signing algorithm:

{
  "alg": "HS256",
  "typ": "JWT"
}

Common algorithms: HS256 (HMAC + SHA256, symmetric), RS256 (RSA + SHA256, asymmetric), ES256 (ECDSA, asymmetric). The algorithm choice affects security architecture — symmetric keys are simpler but must stay secret on both sides.

Payload

Contains the claims — the actual data you want to transmit:

{
  "sub": "user_123",
  "name": "John Doe",
  "role": "admin",
  "iat": 1516239022,
  "exp": 1516242622
}

Standard claims:

Signature

Created by signing the header + payload with a secret key. This prevents tampering — if anyone modifies the payload, the signature will not match.

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

Common Mistakes

1. Storing sensitive data in the payload

The payload is encoded, not encrypted. Anyone can decode it with a Base64 decoder. Never put passwords, credit card numbers, or private keys in a JWT.

2. Not checking expiration

Always validate exp on the server side. A common bug: checking expiry only on the frontend (which is easily bypassed). Our JWT Expiry Checker helps you quickly verify token timing during development.

3. Using algorithm "none"

Some libraries accept tokens with "alg": "none" — meaning no signature verification. Always reject unsigned tokens in production. Whitelist allowed algorithms explicitly.

4. Symmetric secrets that are too short

For HS256, your secret should be at least 256 bits (32 bytes) of random data. A short string like "secret123" is brute-forceable.

5. Not rotating secrets

If your signing key is compromised, all tokens ever issued are compromised. Rotate keys periodically and support multiple valid keys during transitions.

Debugging JWT Issues

When authentication fails, decode the token first to understand what you are working with:

  1. Decode the header — is the algorithm what you expect?
  2. Decode the payload — are the claims correct? Is sub the right user?
  3. Check exp — is the token expired? Clock skew between servers can cause false expiry.
  4. Check iss and aud — do they match your expected values?
  5. Verify signature — this requires the secret/public key. If verification fails, the token was tampered with or signed with a different key.

JWT vs Sessions

JWTs are stateless — the server does not need to store session data. This scales well but makes revocation hard (you cannot "invalidate" a token without a blacklist). Sessions are stateful but trivially revocable.

For most web apps, short-lived JWTs (15 minutes) combined with a longer-lived refresh token stored in an HTTP-only cookie is a solid pattern.

Tools for JWT Work

DevKit offers three JWT-related tools for your workflow: