Decode JSON Web Tokens online, inspect header and payload claims, check expiry and verify supported HMAC signatures locally.
Decoding never checks the signature — anyone can read an unverified token. For HMAC tokens (HS256 / HS384 / HS512) you can verify it below; your secret is used only in the browser and is never sent anywhere. RSA / ECDSA tokens need the issuer's public key and aren't verifiable here.
A
JWT
is three Base64URL-encoded segments joined by dots:
header.payload.signature. The
header
names the signing algorithm (alg) and token type (typ); the
payload
carries the claims — standard ones like
iss,
sub,
exp
plus any custom fields; the
signature
is computed over the first two segments so the token can't be tampered with undetected.
A JWT decoder is useful for reading authentication claims, debugging expiry, checking issuer and audience values, and confirming which algorithm a token declares. Decoding is not the same as verifying. The header and payload are merely encoded, not encrypted — anyone can read them, which is why you should never put secrets in a JWT. Only checking the signature against the issuer's key proves the token is authentic and unaltered. This tool decodes everything client-side and can verify HMAC signatures locally; the token never leaves your machine.
Many HS256 tokens start with the same first segment,
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
, because it is simply the Base64URL form of this common header — which is also why so many JWTs begin with
eyJ, the encoding of
{":
{
"alg": "HS256",
"typ": "JWT"
}
A typical access-token payload decodes to something like:
{
"iss": "https://auth.example.com",
"sub": "user-1234",
"aud": "api.example.net",
"iat": 1767225600,
"exp": 1767229200,
"scope": "read:reports"
}
The status bar shows the algorithm (HS256), the type (
JWT
), the number of segments and an
Active
or
Expired
tag. In the Claims panel,
iat
is rendered as
Thu, 01 Jan 2026 00:00:00 GMT
and
exp
as
Thu, 01 Jan 2026 01:00:00 GMT
, each followed by a relative time such as “in 5 minutes” or “2 hours ago” — so this token was valid for one hour.
scope
is listed as a custom claim. Use
Load sample
to fill in a demo HS256 token together with its secret and try the Verify button.
| Claim | Meaning | What the decoder shows |
|---|---|---|
iss |
Issuer — the service that created the token | The raw value |
sub |
Subject — usually a user or client ID | The raw value |
aud |
Audience — the API or app the token is meant for (string or array) | The raw value; arrays are shown as JSON |
exp |
Expiration time, in Unix seconds | UTC date, relative time and an Active / Expired tag |
nbf |
Not before — the token must be rejected earlier than this | UTC date, relative time and a Not yet valid tag when it is in the future |
iat |
Issued at, in Unix seconds | UTC date and relative time |
jti |
JWT ID — a unique identifier, often used to block replay | The raw value |
Registered claims are listed first, followed by every other field as a custom claim (for example
scope,
role
or
email). Time claims are seconds since 1970-01-01 UTC, not milliseconds; the
Unix timestamps guide
explains the format, and the
Timestamp Converter
converts individual values.
The alg header names how the signature was produced. This page can verify only the HMAC family:
| alg | Type | Key needed | Verify here? |
|---|---|---|---|
HS256, HS384, HS512 |
HMAC with SHA-2 | Shared secret | Yes, in the browser via Web Crypto |
RS256, PS256, ES256, EdDSA and variants |
RSA, RSA-PSS, ECDSA, EdDSA | Issuer's public key (often from a JWKS URL) | No — decode only |
none |
Unsecured token | None — there is no signature | No — never reported as verified |
The green Valid JWT verdict means only that the header and payload are well-formed Base64URL-encoded JSON. Anyone can edit a payload, re-encode it and paste it here; it will decode just as cleanly. Only a matching signature, checked with the right key, shows the token was issued by the expected party and not altered.
A token with
"alg": "none"
carries no signature, so anyone can mint one with any claims. A server must never accept it, and should not let the token's own header choose the algorithm: configure the expected algorithm (and key) on the verifier. The same rule prevents algorithm confusion, where an RS256 public key is misused as an HS256 secret.
exp
has passed,
nbf
is still in the future, or
aud
and
iss
differ from what the API expects.
alg
an identity provider uses and which custom claims (roles, scopes, tenant IDs) it adds.
| Symptom | Likely cause | Fix |
|---|---|---|
| “A JWT needs at least 2 dot-separated segments” | Only part of the token was copied, or it is an opaque (non-JWT) access token | Copy the full value; opaque tokens can only be inspected by their issuer |
| “Header is not valid Base64URL-encoded JSON” | A Bearer prefix, surrounding quotes or a cookie name was pasted with the token |
Paste only the part starting with eyJ |
| “Payload is not valid Base64URL-encoded JSON” | Truncated token, or an encrypted JWE (five segments) | Re-copy the token; a JWE must be decrypted by its recipient |
| “Signature does not match” with the right secret | The secret is stored Base64-encoded, or has extra whitespace | Paste the secret exactly as the signer uses it; this tool treats it as UTF-8 text |
| Expired here, but the API still accepts it | Your device clock differs, or the server allows clock-skew leeway | Compare exp with the current Unix time |
| Dates tens of thousands of years in the future | Time claims written in milliseconds instead of seconds | Fix the issuer to use seconds, as the JWT spec requires |
header.payload.signature
form is supported, not the JSON serialization.
exp
and
nbf
with your device clock, without leeway, and only when they are numbers.
iat
is displayed but not checked.
iss,
aud
and custom claims are shown, not validated — the decoder cannot know which values your API expects. A verified signature also does not mean the token is unexpired.
No. Splitting, Base64URL decoding, claim inspection and supported HMAC signature checks run in your browser. Nothing is uploaded, but avoid pasting sensitive production tokens on shared or untrusted devices.
No. Decoding only reads the header and payload. A JWT can be readable yet forged. Use the Signature panel to verify HMAC tokens against the shared secret; RSA and ECDSA tokens require the issuer public key and are not verified here.
The exp claim is a Unix timestamp in seconds. If it is in the past, the token is expired. The nbf claim means not before; if it is in the future, the token is not valid yet. The check uses your device clock.
No. The header and payload are Base64URL-encoded, not encrypted. Anyone holding the token can read those claims, so keep passwords, API keys and private personal data out of JWT payloads.
No. A JWE has five segments and its content is encrypted, so the decoder reports that the payload is not valid Base64URL-encoded JSON. Only the intended recipient, holding the decryption key, can read it.