JWT decoder
Paste a JSON Web Token to see its header and claims, with timestamps converted to dates and the common mistakes pointed out. Decoding happens in this page; nothing is sent anywhere.
Do not paste production tokens into websites. This page sends nothing, but a valid token works like a password until it expires. Use a test token, an expired one, or one from a development environment. The signature is decoded, never verified.
- WarnExpired 12 days ago
A correct server rejects it. Note that this is judged by your device's clock.
- InfoHS256: HMAC with SHA-256 (shared secret)
Whoever can verify an HMAC token can also create one, because the same secret does both. Fine inside one service; for tokens checked by several parties, an asymmetric algorithm (RS256, ES256, EdDSA) is safer. The secret needs to be long and random: short secrets can be brute-forced offline from any captured token.
Header
{
"alg": "HS256",
"typ": "JWT"
}Payload
{
"iss": "https://auth.example.com",
"sub": "user_8431",
"aud": "api.example.com",
"iat": 1790000000,
"exp": 1790003600,
"scope": "read:orders write:orders",
"email": "jane@example.com"
}Claims explained
| iss — Issuer: who created and signed the token | https://auth.example.com |
|---|---|
| sub — Subject: who the token is about, usually a user ID | user_8431 |
| aud — Audience: who the token is meant for; others must reject it | api.example.com |
| iat — Issued at | 1790000000 → 2026-09-21 14:13:20 UTC (12 days ago) |
| exp — Expires at | 1790003600 → 2026-09-21 15:13:20 UTC (12 days ago) |
| scope — Permissions granted (OAuth 2.0) | read:orders write:orders |
| email — Email address | jane@example.com |
Signature
32 bytes. Not verified. Checking it needs the issuer's key; do that in your own code with a maintained JWT library, never by trusting a decoder.
How a JWT is put together
A JSON Web Token (RFC 7519) in its usual signed form is three base64url-encoded parts joined by dots:
header.payload.signature. Base64url is ordinary base64 with - and
_ in place of + and /, and no padding, so the token is safe in URLs
and headers. The header and payload are JSON; the signature is raw bytes computed over the first two
parts exactly as they appear, dots included. An encrypted token (JWE) has five parts instead, and its
payload cannot be read without the key.
Decoding is just the reverse of that encoding. This page splits the token, decodes each part, parses the JSON, and then reads the claims. Dates in JWTs are NumericDate values: whole seconds since 1 January 1970 UTC, not milliseconds.
The registered claims
| Claim | Name | What a server should do with it |
|---|---|---|
| iss | Issuer | Accept only issuers it trusts |
| sub | Subject | Identify the user or client |
| aud | Audience | Reject tokens not meant for it |
| exp | Expiration time | Reject after this moment, allowing a little clock skew |
| nbf | Not before | Reject before this moment |
| iat | Issued at | Optional age limits |
| jti | JWT ID | Detect a token being replayed |
Signing algorithms
The alg header names one of the algorithms in RFC 7518 (JWA) or RFC 8037. The practical
split is between symmetric HMAC (the HS family), where one shared secret both signs and verifies, and
asymmetric signatures, where a private key signs and anyone with the public key can verify.
| alg | Meaning |
|---|---|
| HS256 | HMAC with SHA-256 (shared secret) |
| HS384 | HMAC with SHA-384 (shared secret) |
| HS512 | HMAC with SHA-512 (shared secret) |
| RS256 | RSA PKCS#1 v1.5 with SHA-256 |
| RS384 | RSA PKCS#1 v1.5 with SHA-384 |
| RS512 | RSA PKCS#1 v1.5 with SHA-512 |
| PS256 | RSA-PSS with SHA-256 |
| PS384 | RSA-PSS with SHA-384 |
| PS512 | RSA-PSS with SHA-512 |
| ES256 | ECDSA P-256 with SHA-256 |
| ES384 | ECDSA P-384 with SHA-384 |
| ES512 | ECDSA P-521 with SHA-512 |
| EdDSA | EdDSA (usually Ed25519) |
| none | No signature |
A worked example
The example token's header is {"alg":"HS256","typ":"JWT"}. Its payload says it was
issued by https://auth.example.com for user user_8431, to be used by
api.example.com, with the scopes read:orders write:orders.
iat is 1790000000, which is 2026-09-21 14:13:20 UTC, and exp is 1790003600,
exactly 3,600 seconds (one hour) later. That is a typical access-token lifetime, and it means the token
has long since expired: any correct server would reject it now. The algorithm is HS256, so the API
that checks it must hold the same secret as the issuer; for a token accepted by several services an
asymmetric algorithm such as ES256 or RS256 would keep the ability to create tokens in one place.
What decoding cannot tell you
Whether the token is genuine. Anyone can write a token with any claims they like; only checking the
signature with the right key, and then checking iss, aud, exp and
nbf, establishes that it is real and current. Expiry on this page is judged by your
device's clock. Claims beyond the registered ones are explained where they are widely used (OAuth
scopes, OpenID Connect profile claims), but their meaning is ultimately whatever the issuer decided.
Common questions
Is it safe to paste a token here?
Nothing leaves your browser: the page makes no network request when you paste, which you can confirm in the Network tab of the developer tools. Even so, a live token is a password for as long as it is valid, so the habit worth having is to decode test tokens or expired ones, and not paste production tokens into any website, this one included.
Why is the signature not verified?
Verifying needs the key: the shared secret for HS256, or the issuer's public key for RS256 and ES256. A decoder that asked for your secret would be asking you to paste the one thing that must stay private. Verify in your own code with a maintained JWT library, which also checks exp, nbf, iss and aud for you.
Can anyone read the contents of a JWT?
Yes. A normal signed JWT (JWS) is base64url-encoded, not encrypted; anyone holding it can read every claim, as this page shows. The signature only proves nobody changed it. If the contents must be secret, use an encrypted JWT (JWE, five parts instead of three) or keep the data on the server.
What is the difference between an ID token and an access token?
In OpenID Connect, the ID token is a JWT for the client application, describing who logged in (sub, email, name) and it should not be sent to APIs. The access token is for calling APIs; it may or may not be a JWT, and the client should treat it as opaque. If you can decode an access token, that is a detail of the provider, not something to depend on.
What does "alg: none" mean and why is it dangerous?
It declares that the token has no signature. RFC 7519 allows such "unsecured" tokens, but a server that accepts them lets anyone forge a token by editing the payload and deleting the signature. Several JWT libraries shipped with exactly this flaw around 2015; modern ones reject alg=none unless explicitly told otherwise.