What Are JWT Tokens and How to Decode Them

JWTs are signed tokens for authentication and authorization. Learn the format, claims, verification steps, and common security mistakes.

JWT (JSON Web Token) is a token format used to pass signed identity and authorization data between systems.

Quick Answer

A JWT has three parts: header.payload.signature.
The header says how the token was signed, the payload contains claims (like user ID and expiration), and the signature proves integrity.
You can decode a JWT without a secret key, but you must verify the signature before trusting any claim.
For day-to-day debugging, the most important checks are: alg, exp, aud, iss, and signature validity.

What a JWT Is (One-Sentence Definition)

A JWT is a compact, URL-safe signed token that carries JSON claims and can be validated cryptographically.

JWT Format: Header, Payload, Signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

1) Header

The header includes token metadata, usually type and algorithm:

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

Typical values:

  • HS256: HMAC + SHA-256 (shared secret)
  • RS256: RSA + SHA-256 (private/public key pair)
  • ES256: ECDSA + SHA-256 (elliptic curve keys)

2) Payload

The payload contains claims. Claims are statements about the token and subject:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}

3) Signature

The signature protects integrity. If payload data changes, signature verification fails.

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

Standard Claims to Know

Claim Name Purpose
iss Issuer Who created the token
sub Subject Who the token is about (user ID)
aud Audience Who the token is for
exp Expiration When the token expires (Unix timestamp)
nbf Not Before Token not valid before this time
iat Issued At When the token was created
jti JWT ID Unique identifier for the token

Decoding vs Verifying

Decoding means reading the Base64URL data. It does not prove trust.

Verifying means checking the signature with the correct key. This proves integrity and issuer authenticity.

If you only decode and skip verification, anyone can forge claims and your app may trust fake data.

How JWT Authentication Usually Works

  1. User logs in and the server authenticates credentials.
  2. Server issues a JWT with claims (sub, exp, aud, etc.) and signs it.
  3. Client sends JWT on later requests, commonly in the Authorization header.
  4. Server verifies signature and validates claim rules before granting access.
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Worked Examples

Example 1: Valid access token

A payload might include:

{
  "iss": "auth.example.com",
  "sub": "user_42",
  "aud": "api.example.com",
  "iat": 1760000000,
  "exp": 1760003600
}

Interpretation:

  • Token is for api.example.com.
  • It expires one hour after issue.
  • Server should accept it only if signature is valid and clock checks pass.

Example 2: Expired token

{
  "sub": "user_42",
  "exp": 1700000000
}

If current Unix time is greater than 1700000000, token is expired and should be rejected.

Example 3: Audience mismatch

A token may be validly signed but still invalid for your service if aud does not match your API.

Security Considerations

Use this checklist:

  • Always verify the signature before trusting claims
  • Validate exp, nbf, iss, and aud
  • Reject unexpected algorithms and never allow alg: none
  • Keep expirations short for access tokens
  • Avoid sensitive data in payloads (payload is readable)
  • Send only over HTTPS
  • Avoid tokens in URL query strings (URLs are logged)

JWT vs Server Session Cookies

Feature JWT Server Session
Server storage None Session store
Stateless Yes No
Revocation Difficult Easy
Cross-domain Easy Tricky
Payload visibility Readable (unless encrypted token format) Opaque ID

Common JWT Mistakes

  • Treating decode as verification
  • Missing audience (aud) checks
  • Using long-lived access tokens
  • Storing secrets in payload
  • Failing to rotate signing keys
  • Forgetting clock skew handling

Debugging Order That Works

  1. Decode header and payload to inspect claims.
  2. Confirm algorithm is expected (HS256/RS256/etc.).
  3. Validate signature with the correct key.
  4. Check exp/nbf against current Unix time.
  5. Validate iss and aud against your expected values.

Decision Rules

Use JWT when:

  • You need stateless authentication across multiple services.
  • You want tokens validated independently by different backends.
  • You need standard claims and interoperable auth patterns.

Avoid JWT when:

  • You need immediate server-side logout/revocation with simple control.
  • You want minimal token size and opaque identifiers.
  • You might accidentally place sensitive data in token payloads.
Try It

JWT Decoder + Expiry Checker

Decode token parts, inspect claims, and check `exp`/`iat` timestamps in seconds.

Open JWT Decoder

Apply This With Free Tools

FAQ

Is JWT encryption?

Usually no. Standard signed JWTs (JWS) are signed, not encrypted. Payload data is readable.

Can I trust data after decoding a JWT?

No. Trust only after signature verification and claim validation.

Why does my token fail even with a valid signature?

Claim checks can still fail, such as expired exp, invalid aud, or wrong iss.

What time unit does exp use?

Seconds since Unix epoch (January 1, 1970 UTC), not milliseconds.

Should I put email addresses and roles in JWT payload?

Only if acceptable for visibility. Never place secrets, passwords, or private keys in payload claims.

Is localStorage safe for JWT storage?

It depends on your threat model. XSS risks are relevant. Many systems prefer secure, HTTP-only cookies for session tokens.

What is clock skew and why does it matter?

Small client/server clock differences can cause temporary exp or nbf failures. Many systems allow a short tolerance window.

What does jti do?

jti is a unique token ID often used for replay protection or denylist checks.

Related Tools