Json Web Viewer
All tools

JWT Decoder — decode a JSON Web Token's header and payload

Paste a JWT and instantly see what's actually inside it — the header and payload, decoded and readable, with every standard claim explained in plain English — entirely in your browser, locally, and offline.

A JWT (JSON Web Token) is three base64url-encoded segments separated by dots: header.payload.signature. The header and payload are just base64url-encoded JSON — anyone can decode them without any secret, which is exactly what this tool does. Json Web Viewer's Decode JWT action splits the token, decodes the header and payload back into readable JSON, and — deliberately — leaves the signature alone. Decoding is pure local computation — there's no server call involved at any point, so it works fully offline too, including once the app is installed as a PWA.

That's a real limitation, stated plainly: this tool does not verify the signature. Checking a signature requires the signing secret or public key, which introduces its own security surface (timing attacks, algorithm-confusion attacks like a forged "alg":"none") that has no place in a read-only inspection tool. Use it to read a token while debugging, not to authenticate one.

What "not signature-verified" really means

This is worth stating as plainly as possible, because it's the one fact about this tool that matters most: a token decoding cleanly here proves nothing about whether it's genuine. Decoding a JWT is just reversing base64url encoding — no secret is needed, and nobody would need one to alter a token's payload and re-encode it. The only thing standing between "a JWT that decodes" and "a JWT you should trust" is signature verification against the actual issuer's secret or public key, and this tool deliberately never does that.

Why deliberately, rather than as a missing feature: real signature verification means handling a secret or private key inside a browser tool, and introduces its own attack surface — timing attacks during signature comparison, and algorithm-confusion attacks where a token claims a different (often weaker, or absent) algorithm than the server expects. None of that belongs in what is fundamentally a read-only debugging aid. If you need to know whether a token is authentic, check it against your own backend's real validator — the one that actually holds the signing key — not a browser tool that never sees it.

The clearest illustration of why this distinction matters is a token whose header says "alg": "none". That's a real, valid JWT — the specification permits an unsigned token — and it decodes exactly like any other. But it means the token has no signature at all, and anyone can create or edit one by hand. A server that's misconfigured to accept alg: none will trust a token that proves nothing. Because this is the single most common real-world JWT vulnerability rather than a curiosity, the decoder flags it with an explicit unsigned-token warning instead of quietly explaining it like any other header value.

Standard JWT claims, explained

Every explanation below is either RFC-registered or explicitly labeled as a widely-used convention that isn't — nothing is invented for a field the registry doesn't recognize.

JOSE header parameters (RFC 7515 §4.1):

Registered payload claims (RFC 7519 §4.1) — all seven:

exp, nbf, and iat also get a relative reading as of the moment you decoded — "expired ~3 years ago", "expires in ~47 minutes" — so the most common debugging question, is this token expired, is answered without doing date math by hand.

Conventional claims (OIDC / OAuth 2.0 — widely used, but not RFC 7519-registered):

Anything outside these two lists is shown with its raw value and no explanation. That's a deliberate choice, not a gap the registry will eventually fill: a wrong guess at what a custom claim means is worse than admitting it isn't recognized.

Common JWT mistakes

Example — this token:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

decodes to this header and payload, with each standard field explained:

{
  "header": { "alg": "HS256", "typ": "JWT" },
  "payload": { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 },
  "claims": { "iat": { "raw": 1516239022, "iso": "2018-01-18T01:30:22.000Z" } },
  "explanations": {
    "header": { "alg": "the cryptographic algorithm used to sign or protect the token (RFC 7515 §4.1.1) …", … },
    "payload": {
      "sub": "subject — the principal the token asserts information about (RFC 7519 §4.1.2)",
      "iat": "issued at — Unix seconds at which the token was issued (RFC 7519 §4.1.6) — issued ~9 years ago (as of decode)",
      …
    }
  }
}

The explanations come from the RFCs, not guesswork: JOSE header parameters (RFC 7515), the seven registered claims of RFC 7519 (iss, sub, aud, exp, nbf, iat, jti), and common OIDC/OAuth claims like azp, nonce, and scope — labeled as conventional, since they aren't RFC-registered. The three timestamp claims also get a relative reading as of the moment you decoded ("expired ~3 years ago", "expires in ~47 minutes"), so the most common debugging question — is this token expired? — is answered without date math. A token whose header says "alg": "none" gets an explicit unsigned-token warning. Claims the registry doesn't recognize are listed with their value and no explanation — a wrong explanation is worse than none.

Open this example in the editor →
The link above pre-loads the token above as plain text. Json Web Viewer auto-detects that it looks like a JWT and shows a Decode as JWT button right in the toolbar — click it to see the decoded result.

Frequently asked questions

Does this JWT decoder verify the signature?

No, deliberately. Verifying a signature needs the signing secret or public key, and brings real security surface (timing attacks, algorithm-confusion) into what is fundamentally a read-only debugging tool. The header and payload are decoded and shown as-is, clearly marked as not verified.

Is my token uploaded or logged anywhere?

No. Decoding happens entirely in your browser, locally — the token you paste is never sent to a server or stored anywhere outside your own device.

Does this JWT decoder work offline?

Yes. Decoding is pure local computation with no server call involved at any point, so it works whether or not you're connected — including once the app is installed as a PWA, which precaches this page along with the rest of the app for full offline use.

What do the exp, iat, and nbf claims mean?

They are standard JWT timestamp claims stored as Unix seconds: iat is when the token was issued, nbf is the earliest time it's valid from, and exp is when it expires. The decoder converts each to a readable ISO 8601 date and adds a relative reading as of the moment you decoded — e.g. "expired ~3 years ago" or "expires in ~47 minutes" — so you can see at a glance whether an expired token is why a request is failing.

Does it explain what each claim means?

Yes. Every standard field gets a plain-English explanation sourced from the RFCs: the JOSE header parameters (alg, typ, kid, and the rest, per RFC 7515), all seven RFC 7519 registered claims (iss, sub, aud, exp, nbf, iat, jti), and common OIDC/OAuth claims like azp, nonce, and scope, which are labeled as conventional rather than RFC-registered. A token with "alg": "none" gets an explicit unsigned-token warning. Claims the registry doesn't recognize are shown with their value and no explanation — nothing is ever guessed.

What's the difference between decoding a JWT and verifying one?

Decoding just reverses the base64url encoding to reveal the header and payload as JSON — no secret or key is needed, and anyone can do it, including someone who tampered with the token. Verifying checks the signature against the issuer's secret or public key and proves the token wasn't altered since it was signed. This tool only decodes. A cleanly decoded token tells you nothing about whether it's genuine — that's what a real backend validator, checking against the actual signing key, is for.

Is a token with "alg": "none" dangerous?

Yes, if a server ever accepts it. An alg of none means the token has no signature at all — anyone can create or edit one by hand, including changing who it claims to represent. This decoder flags it with an explicit unsigned-token warning rather than explaining it like any other header value, because it's the single most common real-world JWT vulnerability, not a curiosity.

The decoder says a claim was issued in the future — what does that mean?

It means the token's iat (issued at) timestamp is later than the current time on the device that decoded it — normally a sign of clock skew between the server that issued the token and whatever machine is checking it, rather than a token from the future. The relative reading calls this out explicitly ("issued … in the future — check for clock skew") instead of just showing a confusing negative duration.