DEVELOPER TOOLS

JWT Decoder & Encoder

Paste a signed (JWS) JSON Web Token to instantly decode its header and payload, check expiry, and optionally verify an HMAC or public-key (RS256, PS256, ES256) signature — or build and sign a new one. Entirely in your browser, nothing uploaded.

🔒 Your token, payload, and any secret you enter are processed entirely in your browser and are never submitted by this tool to our server or any third party, nor saved in browser storage. Third-party analytics tracking is also disabled on this page.

A JWT's structure

A JSON Web Token (RFC 7519) can be serialized one of two ways. The far more common form — what this tool decodes, and what "JWT" usually means colloquially — is JWS Compact Serialization (signed): three base64url-encoded segments joined by dots, header.payload.signature. The header is a small JSON object naming the signing algorithm (alg) and token type (typ, almost always "JWT"). The payload is a JSON object holding the actual claims — whatever data the token is meant to carry. The signature (per RFC 7515, the JSON Web Signature spec) is computed over the header and payload segments together, so that changing either one without knowing the signing key invalidates it. The other form, JWE Compact Serialization (encrypted, five segments), is a genuinely different format this tool doesn't decrypt — see the note below if you paste one in.

Encoded, not encrypted

This is the single most important thing to understand about a signed (JWS) JWT: base64url is an encoding, not encryption. Anyone holding a JWS JWT can decode its header and payload instantly — no key, secret, or password required, which is exactly what this tool itself demonstrates. The signature doesn't hide the contents; it only lets a party who knows the signing key confirm the token wasn't modified after it was issued. An encrypted JWE token is genuinely different — its payload is actually encrypted, not just encoded, and reading it does require the appropriate decryption key. Never put anything genuinely secret (a password, a full credit card number, private personal data beyond what the token's audience should already see) directly in a JWS JWT's payload — treat it the way you'd treat any other value transmitted in the clear.

Standard claims

RFC 7519 §4.1 defines several registered payload claims with specific meanings, though none are strictly required and applications commonly add their own alongside them:

  • exp (expiration time) — a Unix timestamp (seconds since the epoch, not milliseconds) after which the token must be rejected.
  • nbf (not before) — a Unix timestamp before which the token must not be accepted yet.
  • iat (issued at) — the Unix timestamp the token was created.
  • iss (issuer) — identifies who issued the token.
  • sub (subject) — identifies who or what the token is about (often a user ID).
  • aud (audience) — identifies who the token is intended for.
  • jti (JWT ID) — a unique identifier for this specific token, often used to detect replay or track individual tokens.

This tool decodes exp/iat/nbf into human-readable dates automatically and flags an expired, not-yet-valid, or malformed (present but not a usable timestamp) claim directly under the payload.

Verifying a signature

If a token uses an HMAC algorithm (HS256, HS384, or HS512), enter the shared secret it was signed with and click Verify to confirm the signature matches. If it uses RS256, PS256, or ES256, paste the issuer's public key instead — as a PEM key in SPKI format (-----BEGIN PUBLIC KEY-----; PKCS#1 -----BEGIN RSA PUBLIC KEY----- isn't supported directly, but converts with openssl rsa -RSAPublicKey_in -in yourkey.pem -pubout), a single JWK, or a JWKS (the format an OAuth/OIDC provider's own jwks_uri returns) — the tool auto-detects which format you've pasted, and matches the token's own kid against a JWKS with more than one key. Other asymmetric algorithms (RS384/RS512, PS384/PS512, ES384/ES512, EdDSA) aren't verified here yet — it says so directly rather than pretending to check something it can't.

A matching signature only confirms the token wasn't altered by someone without the key — it doesn't by itself confirm the token is the right one for your application. Optionally fill in Expected issuer and/or Expected audience above either Verify section to also check the token's own iss/aud claims against what you expect; this runs automatically right after a successful signature verification.

Building and signing a new JWT

Switch to Encode / Sign above to build a new HMAC-signed token from scratch — useful for testing an API that expects a JWT, without needing a full auth flow just to get one. The algorithm is always chosen from the dropdown, never from editable header JSON, specifically so the token this tool hands back can never claim an algorithm different from the one it was actually signed with. alg: none isn't offered as an encoding option at all, since generating an intentionally-unsigned token isn't something this tool should make easy to do by accident. If the secret you enter is shorter than RFC 7518's own required minimum for the chosen algorithm (the RFC states this with "MUST," not merely a suggestion), the tool refuses to sign with it rather than silently generating a token with a weak key.

Common JWT vulnerabilities

The alg:none attack

A token can declare "alg": "none", meaning no signature at all. A verifier that doesn't explicitly reject this can be fed a completely unsigned, freely-editable token — an attacker just base64url-encodes whatever header and payload they want and appends an empty signature segment. This tool flags alg: none explicitly (and separately flags the case where a signature segment is present anyway, which is itself a structurally inconsistent token), since a correct verifier must always reject unsigned tokens unless the application genuinely intends to accept them, which is rare.

Algorithm confusion (RS256 → HS256)

Some JWT libraries look at the token's own alg header to decide how to verify it, rather than the application fixing the expected algorithm in advance. If a server expects RS256 (asymmetric — verified with a public key) but a vulnerable library will also accept HS256 (symmetric — verified with a shared secret) when the token says so, an attacker who knows the RS256 public key (often not secret at all — it's meant to be shared) can sign a forged token with HS256 using that public key as the HMAC secret. A correctly-configured verifier pins the expected algorithm itself and never trusts the token's own header to decide.

Frequently asked questions

Is this tool safe to paste a real JWT into?

For a signed (JWS) JWT, the header and payload are readable by anyone holding the token — decoding one reveals nothing an attacker with the token couldn't already read themselves, and that's true everywhere, not specific to this tool. Encrypted JWE tokens are different: their payload isn't readable without the appropriate decryption key. Everything happens locally in your browser regardless; nothing is uploaded. If you're testing signature verification or building a new token, treat any secret you enter with the same care you would anywhere else, though it also never leaves your browser.

Why doesn't my token's signature verify, even though I'm sure the secret is right?

The signature covers the exact header and payload segments as they appear in the token — not a re-serialized version of the decoded JSON. If a token was manually edited after signing (even reformatting whitespace) without re-signing it, verification will correctly fail. Also double-check the algorithm: a secret that's correct for HS256 will not verify an HS384 or HS512 signature, since each treats the same secret differently.

Can I decode a JWT without knowing the secret or key?

For a signed (JWS) JWT, decoding the header and payload never requires a secret, key, or verification of any kind — only checking whether the signature is genuinely valid (proving the token wasn't tampered with) needs the signing secret or key. An encrypted JWE token is different: its payload is actually encrypted, not just encoded, so reading it does require the appropriate decryption key.

What's the difference between a JWT and a session cookie?

A traditional session cookie is typically just a random ID that references server-side state; the server looks up who that ID belongs to on every request. A JWT carries its own claims directly, self-contained — the server can verify it without a database lookup. A stateless JWT alone doesn't offer a way to revoke a specific token before it expires; applications that need that typically add a denylist, server-side session state, key rotation, or short expiry times combined with a refresh-token pattern.

Sources

Last reviewed: . Signature verification and signing use the browser's native Web Crypto API — HMAC for HS256/384/512, RSASSA-PKCS1-v1_5 for RS256, RSA-PSS for PS256, and ECDSA for ES256 — not a hand-rolled implementation.

Relevant, Not Routine

New tools and anything else worth knowing — sent occasionally, only when there's something real to say.