Skip to main content

How to Decode a JWT Token Safely (and What Each Part Means)

TL;DR: A JWT is header.payload.signature, each base64url-encoded JSON. Decoding reveals the claims; verifying needs the issuer's key. Use a browser-side decoder (PrivaTools JWT Decoder) — never paste production JWTs into a server-side decoder.

JWT tokens are everywhere in modern web auth. How they're structured, how to decode them, what each claim means, and why you should never paste a real JWT into a random online decoder.

Published: 2026-05-15 · 8 min read · By the PrivaTools team

If you've worked with modern web auth, you've seen tokens that look like this:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZXhwIjoxNzMwMDAwMDAwfQ.signature

That's a JWT — JSON Web Token. It's the standard format for stateless authentication across REST APIs, OAuth flows, and microservice mesh systems. JWTs are not encrypted; they're just signed. Decoding them is trivial. Verifying their signature requires the issuer's secret or public key.

This guide explains the JWT structure, how to decode one, what each standard claim means, and how to decode JWTs without leaking them to a random online service.

The Three Parts of a JWT

Every JWT has three dot-separated parts:

HEADER.PAYLOAD.SIGNATURE

Each part is base64url-encoded. Base64url is regular base64 with two character swaps (+-, /_) and no padding. Some implementations are picky about the padding; most aren't.

1. Header

The header tells you the signing algorithm and the token type:

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

Common alg values:

2. Payload (Claims)

The payload is the JSON object you actually care about. It contains "claims" — assertions about an entity. Decoding shows something like:

{
  "sub": "user-42",
  "iat": 1730000000,
  "exp": 1730003600,
  "iss": "auth.example.com",
  "aud": "api.example.com",
  "scope": "read:profile write:profile"
}

Standard claims (defined by RFC 7519):

Everything else (roles, scopes, custom permissions) is application-specific.

3. Signature

The signature is computed over base64url(header) + "." + base64url(payload) using the algorithm specified in the header and the issuer's secret (HS*) or private key (RS*/ES*). It's there so a recipient can verify the token wasn't tampered with — given the right key.

The signature does NOT make the token confidential. Anyone can decode header and payload. The signature only proves the token came from someone who has the signing key.

How to Decode a JWT

Online (Browser-Side, Safe)

Paste your JWT into PrivaTools JWT Decoder. The token is decoded entirely in JavaScript inside your browser — never sent to any server. You'll see the header, payload (with iat/exp converted to ISO 8601), and signature.

Command Line

# With jq
echo "$TOKEN" | cut -d. -f2 | base64 -d 2>/dev/null | jq

# With Python
python3 -c "import sys,base64,json
parts = sys.argv[1].split('.')
pad = lambda s: s + '=' * (-len(s) % 4)
print(json.dumps(json.loads(base64.urlsafe_b64decode(pad(parts[1]))), indent=2))" "$TOKEN"

What NOT to Do: Public Online Decoders

There are many "JWT decoder" sites that send your token to their server. Some log the token. A logged production JWT is an instant authentication bypass — anyone with the log file can impersonate the user until the token expires.

Always use a decoder that processes the token client-side. Verify by opening DevTools → Network and confirming no outgoing request fires when you paste a token.

Common Mistakes

1. Trusting an unsigned token

An attacker can construct any JWT they want with alg: none and no signature. Many JWT libraries used to accept these. Always validate the algorithm matches what your service expects.

2. Confusing decoding with verification

Decoding shows you what the token claims. Verification proves the claims are authentic. You need the issuer's key to verify. A decoded-but-not-verified token tells you nothing trustworthy.

3. Leaking tokens in URLs

JWTs in URL query strings get logged everywhere — browser history, server access logs, analytics, CDNs. Always pass them in the Authorization: Bearer header.

4. Long-lived tokens

If your exp is days or weeks in the future, a single token theft is a long-lived compromise. Use short-lived access tokens (5–15 minutes) plus refresh tokens for sessions.

5. Storing JWTs in localStorage

localStorage is accessible to any JavaScript on the page. XSS = token theft. Use HttpOnly cookies for browser-side session tokens, or in-memory storage with a sliding refresh.

How to Verify a JWT (Beyond Decode)

Verifying requires:

  1. The signing algorithm from the header.
  2. The corresponding key (secret for HS*, public key for RS*/ES*).
  3. Recomputing the signature over header.payload with that key.
  4. Comparing the recomputed signature against the one in the token.

Use a library — never roll your own. Common picks: jsonwebtoken (Node), PyJWT (Python), jjwt (Java), github.com/golang-jwt/jwt (Go).

FAQ

Is the JWT signature reversible?

No. It's a one-way hash. You can verify it given the key but you can't extract the key from a signature alone (without a brute force attack on a weak secret).

Can I decode a JWT without the secret?

Yes. Header and payload are just base64-encoded JSON. The secret is only needed for verification.

Are JWTs encrypted?

By default, no. They're signed but not encrypted. There IS a sibling spec called JWE (JSON Web Encryption) that adds encryption, but it's much less commonly used.

Is it safe to log JWT payloads in my server logs?

It's safer to log the sub claim (user ID) and the jti claim (token ID) but NOT the full token. The full token would let anyone with log access impersonate the user.

More from the PrivaTools Blog