Skip to content
LocalOnly

JWT Decoder

Stable

Decode a JWT to inspect its header, payload, and claims instantly.

Everything is processed locally in your browser

About JWT Decoder

Paste a JSON Web Token to instantly decode its header and payload and read the claims inside. This online JWT decoder pretty-prints the JSON, highlights registered claims, and translates timestamp fields like exp, iat, and nbf into human-readable dates so you can spot expired tokens at a glance. Decoding is read-only and does not verify the signature.

Features

  • Splits the token into header, payload, and signature and decodes each part
  • Pretty-printed, syntax-highlighted JSON for header and payload
  • Human-readable rendering of exp, iat, and nbf timestamps
  • Expiry check that flags tokens that are expired or not yet valid
  • Recognizes standard registered claims (iss, sub, aud, exp, and more)
  • Handles Base64URL segments with or without padding

How to use JWT Decoder

  1. 1

    Paste the JWT

    Drop in the full token - the three dot-separated Base64URL segments. The tool splits and decodes them automatically.

  2. 2

    Inspect the header

    See the signing algorithm (alg) and token type (typ), plus any key ID (kid) used to select the verification key.

  3. 3

    Read the claims

    Review the payload's claims with timestamp fields converted to readable dates, and check whether the token is currently valid.

Examples

Decode a sample HS256 token

The classic example token decoded into its header and payload.

Input

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Output

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

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

How JSON Web Tokens work

What the three segments contain

A JWT is three Base64url segments joined by dots. The header names the signing algorithm in `alg` and often a key identifier in `kid`, which tells the verifier which public key to use. The payload holds the claims - who the token is about, when it expires, what it grants. The signature covers the first two segments and is what makes the token trustworthy.

The header and payload are encoded, not encrypted. Anyone holding the token can read every claim in it, which is why a JWT must never contain anything confidential. Putting a password, an internal database ID you would rather not expose, or personal data beyond what the client already knows into a JWT is the most common design mistake with the format.

The signature is the part that matters for security and it is unreadable by design - it is raw bytes, not text. Seeing gibberish in the third segment is correct.

Decoding tells you nothing about whether a token is valid

This is the single most important thing to understand about JWTs. Decoding reads the claims. Verification checks the signature against a key and confirms the token has not been forged or altered. They are completely separate operations, and only one of them provides any security.

Anyone can take a valid token, change `"role": "user"` to `"role": "admin"`, re-encode it, and produce a token that decodes perfectly and displays exactly what they want. Nothing about the decoded output would reveal the tampering. Only signature verification catches it, and verification requires the secret or public key.

So a decoder is a debugging aid, not a security check. It is for looking at what a token claims while you work out why a request is being rejected. Verification belongs in your application, using a library, with the key held server-side. Never make an authorisation decision from decoded claims alone.

Algorithms, and the two classic vulnerabilities

HS256 is symmetric: one secret both signs and verifies, so every verifying party can also mint tokens. That is fine within a single service and unacceptable across trust boundaries. RS256 and ES256 are asymmetric: a private key signs and a public key verifies, so you can distribute verification without distributing the ability to issue. For anything multi-party, including OIDC, asymmetric is the correct choice.

The `alg: none` vulnerability comes from libraries that honoured the header's own claim about which algorithm to use. A token declaring `none` with an empty signature was accepted as valid, because the library trusted the attacker-controlled header. Modern libraries reject `none`, but the lesson generalises: never let the token decide how it is verified. Pin the expected algorithm in your verification call.

The confusion attack is the subtler cousin. If a service verifies with RS256 but a library allows the algorithm to be chosen by the header, an attacker can submit an HS256 token signed with the public key as the HMAC secret - and since the public key is public, they can sign it themselves. Pinning the algorithm prevents both.

The registered claims and how they are checked

`exp` is the expiry as a Unix timestamp in seconds, and it is the most important one to validate. A common bug is passing milliseconds, which yields a date in the year 55,000 and a token that never expires. `iat` is when the token was issued and `nbf` is the earliest time it becomes valid.

`iss` and `aud` identify the issuer and the intended audience, and both should be validated. Skipping `aud` means a token issued for a different service in the same ecosystem will be accepted by yours - a genuine privilege escalation path in multi-service environments.

`sub` identifies the subject, and `jti` is a unique token identifier that supports revocation lists. Revocation is JWT's real weakness: a stateless token stays valid until it expires, so there is nothing to invalidate. The standard mitigations are short expiry with refresh tokens, or a server-side deny list keyed on `jti` - which reintroduces the state that JWTs were meant to avoid.

Reference

Registered claims

ClaimMeaningValidation note
issIssuerCheck against an expected value
subSubject - who the token is aboutYour user identifier
audAudience - who it is forMust be validated or cross-service reuse is possible
expExpiry, Unix secondsSeconds, not milliseconds
nbfNot valid beforeAllow small clock skew
iatIssued atUseful for age-based policies
jtiUnique token idNeeded for revocation lists

Which tool should you use?

These tasks overlap. Here is how to pick the right one for what you are actually doing.

You are debugging why an API rejects a token
Decode it and check `exp`, `aud` and `iss` first. Expiry and audience mismatches account for most rejections.
You need to confirm a token is genuine
A decoder cannot do this. Verify the signature in your application with a library and a server-held key.
You want to read the timestamp claims as dates
The Timestamp Converter turns `exp` and `iat` into readable dates, which makes off-by-1000 errors obvious.
You have a single Base64 segment rather than a whole token
The Base64 Decode tool handles it - use the URL-safe variant, since JWT segments are Base64url.

Use cases

  • Debugging authentication and authorization during development
  • Checking a token's expiry and issued-at times while troubleshooting
  • Confirming which scopes, roles, or audience a token carries
  • Inspecting the kid and alg header before configuring verification
  • Understanding an unfamiliar identity provider's claim structure

Troubleshooting common errors

The token is rejected as expired but looks current

Why: `exp` in milliseconds instead of seconds, or clock skew between the issuer and the verifier.

Fix: Confirm `exp` is seconds - a 13-digit value is milliseconds. Allow 30-60 seconds of leeway for skew.

"Invalid signature" on a token you believe is correct

Why: The wrong key, the wrong algorithm, or a token altered in transit. With RS256, the `kid` may point to a rotated key.

Fix: Confirm the key matches the `kid`, and that your verifier pins the same algorithm the issuer used.

The third segment is unreadable

Why: It is the signature - raw bytes rather than text.

Fix: Correct behaviour. Only the header and payload are meant to be readable.

The token works against one service and not another

Why: An `aud` mismatch - it was issued for a different audience.

Fix: Request a token for the correct audience. That the other service accepted it may mean it is not validating `aud` at all, which is itself worth fixing.

You cannot log a user out before their token expires

Why: JWTs are stateless; there is nothing server-side to invalidate.

Fix: Use short-lived access tokens with refresh tokens, or keep a deny list keyed on `jti`. This is an inherent trade-off of the format.

Limitations

What this tool deliberately does not do, so you know when to reach for something else.

  • Decoding is not verification and provides no security guarantee whatsoever.
  • Claims are readable by anyone holding the token, so a JWT must not carry secrets.
  • Encrypted tokens (JWE) are not readable without the decryption key.
  • A token cannot be revoked before expiry without server-side state.
  • The signature cannot be checked here, since that requires a key that should never leave your server.

Frequently asked questions

Learn more

Command Palette

Search for a tool or command