Skip to content
JWT Decoder

JWT decoder — read a token without handing it to anyone

Paste a JSON Web Token to see its header and payload decoded and pretty-printed, with exp, iat and nbf written out as real dates and the expiry worked out for you. The token is decoded by this page, inside your browser — it is never sent anywhere, because there is no server to send it to. That matters more here than on any other tool on this site: a JWT is a live credential, and every other decoder on the web receives yours.

  • Your token never leaves this tab — nothing is uploaded or saved
  • It decodes. It does not verify a signature
  • Works offline once the page has loaded
Your token

This token is decoded here, in your browser. It is not uploaded, not logged and not saved — there is no server behind this page to send it to. Close the tab and it is gone.

What the token says about itself
Algorithm
HS256
Type
JWT
Key id
2026-08-key-1

Checking the expiry against your clock…

Signature (segment 3)

8Qv3rXkZC1nO7uYb2mJ5tGxA9dPfLwHsRq0KeVi4NcU

32 bytes once decoded. Shown as-is — see the note below for why it is not checked.

This page decodes a token. It does not verify one.

Checking a signature needs the secret or the public key that signed the token. This page has neither, never asks for either, and could not use one if you pasted it. So nothing below tells you a token is genuine — only what it claims about itself, and a claim is written by whoever made the token. Anyone can compose a payload that says admin and encode it; the signature is the only thing that would catch them, and it is checked in your service, not here. Remember too that a JWT is signed, not encrypted: everything below was readable by anybody holding this token, which is exactly why “it is just Base64” is not a place to keep a secret.

Header — segment 1
  • "alg": "HS256"
  • "typ": "JWT"
  • "kid": "2026-08-key-1"
}
Payload — segment 2
  • "iss": "https://auth.example.com"
  • "sub": "user_8412"
  • "aud": "utilifyhub-demo"
  • "iat": 1785921120
  • "nbf": 1785921120
  • "exp": 1785924720
  • "jti": "b7c1f0e2-4d3a-4f19-9c2e-0a51d8f6b3a7"
  • "name": "Nurul Aisyah binti Zulkifli"
  • "email": "nurul@example.com"
  • "roles":
    • 0: "editor"
    • 1: "billing"
    ]
  • "note": "Café · 日本語 · emoji 🇲🇾"
}
Registered claims, in human form

Only the claim names defined by RFC 7519 are interpreted here. Everything else in the payload belongs to whoever issued the token, and is shown above exactly as it arrived.

Expires at (exp)2026-08-05 10:12:00 UTC

1785924720 · local time appears once the page has loaded

After this instant the token must be rejected. It is a hard deadline, not a hint — nothing revokes the token before it, and nothing can extend it after.

Not before (nbf)2026-08-05 09:12:00 UTC

1785921120 · local time appears once the page has loaded

Before this instant the token must also be rejected. It exists so a token can be minted ahead of the moment it is allowed to work.

Issued at (iat)2026-08-05 09:12:00 UTC

1785921120 · local time appears once the page has loaded

When the token was created. Some services use it to reject tokens older than a set age, independently of exp.

Issuer (iss)https://auth.example.com

Who issued the token. Your server should check this matches the issuer you trust.

Subject (sub)user_8412

Who the token is about — usually a user id, not an email or a name.

Audience (aud)utilifyhub-demo

Who the token was made for. A service must reject a token addressed to a different audience.

JWT ID (jti)b7c1f0e2-4d3a-4f19-9c2e-0a51d8f6b3a7

A unique id for this token, used to revoke it or to stop it being replayed.

What the three segments are

A JWT is three Base64URL strings joined with dots. Each one has a job, and the difference between them is the difference between reading a token and trusting it.

Header — segment 1

A small JSON object describing how the token was signed. alg names the algorithm (HS256 uses a shared secret; RS256 and ES256 use a key pair). typ is "JWT". kid, when present, names which key from the issuer's published key set was used, so a service can pick the right one without guessing. This segment is read before anything is trusted, which is why a service must never simply do what alg tells it — accepting "none" from the header is a well-known way to be handed a forged token.

Payload — segment 2

The claims. Seven names are registered by RFC 7519 — iss, sub, aud, exp, nbf, iat and jti — and everything else belongs to whoever issued the token: roles, email, tenant, permissions. It is Base64URL, so it is readable by anyone holding the token, and it is signed, so it cannot be changed without detection. Both of those are true at once, and confusing them is the most common mistake made with JWTs.

Signature — segment 3

The first two segments, joined with a dot, run through the algorithm from the header with a key. A service recomputes it and compares. If they differ, the token was altered or was never issued by that key. This is the segment this page cannot check, because doing so needs the key — and the length shown here is the only thing about it that can be read without one.

How it works

  1. 1

    Paste the token

    Decoding happens as you type — there is no button. A leading "Bearer", surrounding quotes and any line breaks from a wrapped terminal are stripped before parsing, because none of those are part of the token. If the input is not a JWT at all, you get a sentence saying which segment is wrong and why, rather than a blank panel.

  2. 2

    Read the header

    The header is small and says how the token was signed: alg names the algorithm, typ is almost always "JWT", and kid points at which key from the issuer's key set was used. When alg is "none" the token carries no signature at all — this page says so plainly, because an unsecured token is one that anybody can write.

  3. 3

    Read the payload, and the dates

    The payload is shown two ways. The registered claims — iss, sub, aud, jti — are labelled with what they mean, and exp, iat and nbf are printed as readable dates in UTC and in your own time zone, with the expiry stated in plain words: expired two hours ago, or four days left. Everything else is your issuer's own data and is shown exactly as it appears, as a JSON tree.

  4. 4

    Then verify it somewhere that can

    This page reports the signature's length and nothing more. Checking a signature needs the HMAC secret or the public key that produced it, and a web page has no business asking you for either. Verification belongs in your service, with a library that fetches the issuer's JWKS and checks alg, iss, aud and exp together.

Frequently asked questions

Is my token uploaded anywhere?

No. The decoder is JavaScript running in this page, on your device. There is no server behind this site — it is static files on a CDN — so there is nowhere for a token to be sent even by accident. Nothing is written to localStorage either: close the tab and the token is gone. That is the whole reason this page exists, because a JWT is a working credential and most decoders on the web receive yours before showing it to you.

Does this tell me whether a token is valid?

No, and it deliberately never will. Validity means the signature checks out against the key that issued the token, and this page does not have that key. What you get instead is what the token claims about itself: the algorithm named in the header, and whether the exp and nbf timestamps put it inside its own window. A decoder that showed a green tick would be reporting on data an attacker fully controls.

Is a JWT encrypted?

A normal JWT is signed, not encrypted. The header and payload are Base64URL — an encoding, not a cipher — so anyone holding the token can read every claim in it, which is exactly what this page does. The signature stops the contents being changed; it does not hide them. Never put anything in a payload you would not be willing to show the person carrying the token. Encrypted tokens do exist (JWE, five segments instead of three) and their payload genuinely cannot be read without the key.

What do exp, nbf and iat actually mean?

They are NumericDate values from RFC 7519: seconds since 1 January 1970 UTC, written as a plain JSON number. exp is the instant after which the token must be rejected. nbf is the instant before which it must also be rejected, which lets a token be minted ahead of the moment it starts working. iat records when it was issued, and some services use it to reject anything older than a set age. Note the unit — they are seconds, not milliseconds, and treating them as milliseconds puts every token in 1970.

Why is pasting a production token into a website a bad habit?

Because until it expires, the token is the account. Anyone who holds it can make requests as that user, and nothing about copying it into a form makes that less true — the receiving site could log it, and you would have no way to tell. The right habit is to use tokens from a test environment, or a decoder that runs locally. This one runs locally, which is why it is safe to use, but the habit is worth keeping even here.

What is the signature segment for, and why is only its length shown?

The signature is computed over the encoded header and payload with a secret (HS256) or a private key (RS256, ES256), and it is what makes tampering detectable: change one character of the payload and the signature no longer matches. Its length is a real signal — HS256 and ES256 produce 32 bytes, HS512 produces 64, RS256 produces 256 — so a length that disagrees with the alg in the header is worth a second look. Checking the signature itself would mean asking you for the key, and no web page should.

Can I change a claim and get a working token back?

Not here, and not anywhere without the signing key. Editing a payload invalidates the signature, and any service checking it properly will reject the result. That is the point of signing. Tools that offer to re-sign a token ask for your secret in order to do it, which is a thing to be wary of typing into a browser at all.