simpletool.io

JWT Encoder/Decoder

Decode JWT header and payload, verify signatures locally.

Decoding and signing run in your browser. Tokens and secrets never leave your device.

HS256/384/512 supported · RS/ES require a public key (roadmap)

JWT

Paste a secret to verify the signature.
Header · algorithm
{
  "alg": "HS256",
  "typ": "JWT"
}
Payload · claims
{
  "sub": "1234",
  "name": "Ada Lovelace",
  "iat": 1710000000,
  "exp": 2000000000
}
Issued at (iat)
2024-03-09T16:00:00.000Z
Expires (exp)
2033-05-18T03:33:20.000Z
Signature (raw)Qb3q14k7VFAJx6hLzO0i5e4Gss_e2JZBVXrdFSW8_3s

What is a JWT Encoder / Decoder?

A JSON Web Token (JWT) is a compact, URL-safe way to transport a set of signed claims between two parties. Authentication systems emit them to prove a user is logged in; authorisation services use them to carry permissions; API gateways use them to relay a user identity downstream. Every JWT has three parts separated by dots: a header that names the signing algorithm, a payload that holds the claims, and a signature that binds the first two together under a secret or private key. Tampering with the header or payload after signing invalidates the signature, so the recipient can trust the claims without re-contacting the issuer.

The wire format is three Base64URL-encoded segments joined by dots. Base64URL (the URL-safe variant of Base64, swapping +/ for -_ and stripping padding) means the token can travel in HTTP headers, query strings, and cookies without further escaping. That compactness matters: Authorization: Bearer eyJ… is the canonical HTTP pattern, and your application sees that header on every request.

Decoding is trivial — anyone with the token can read the header and payload with no secret. JWT is signed, not encrypted. Treat the payload as public; never put passwords, API keys, or PII there unless you're also using JWE (JSON Web Encryption, a separate spec). Sensitive claims should live in a server-side session with the JWT carrying only a session ID. The signature is what makes the claims trustworthy, not secret.

Our tool runs in two modes. Decode splits any JWT into its three parts, pretty-prints the JSON, surfaces the standard time claims (iat issued-at, nbf not-before, exp expiry) as human-readable ISO dates, and flags an expired token with a red label. Paste an HMAC secret and we verify the signature in the browser via the jose library. Encode takes a header and payload as JSON and signs a token with an HMAC secret — useful for quick test tokens during development.

Signature algorithms fall into three families. HS* (HS256, HS384, HS512) use HMAC with a shared secret — fast, simple, everyone who can verify can also sign. Use for internal service-to-service tokens. RS* (RS256…) use RSA with an asymmetric key pair; the private key signs, the public key verifies. Use when issuers and verifiers are different services. ES* (ES256…) use elliptic-curve signatures; similar properties to RS but with smaller keys and faster verification. Our tool currently supports the HS family — RS and ES require public-key parsing and are on the roadmap.

Security gotchas. Accept only the algorithms your system needs, and never accept alg: none — a famous early JWT bug. Rotate secrets; use at least 32 bytes of random data for HS256. Set an exp on every token and keep expiries short (minutes, not days) — use refresh tokens for longer sessions. Finally, do not roll your own JWT library in production; stick with battle-tested implementations (jose, jsonwebtoken, pyjwt, jjwt).

Privacy: token and secret stay in your browser. That matters because a real JWT often carries enough data (user ID, email, internal roles) that pasting it into an unknown tool is a potential leak risk. This decoder runs locally.

How to use the JWT Encoder / Decoder

  1. Pick decode or encode. Tabs at the top flip the mode.
  2. In decode mode, paste a token. The header, payload, and signature appear on the right with time claims already converted to readable dates.
  3. Paste the HMAC secret to verify the signature; a green or red badge tells you if it checks out.
  4. In encode mode, edit the header and payload as JSON, then click Sign.
  5. Copy the decoded parts or the signed token; every panel has its own copy button.

Features

  • Decode any JWT — header, payload, and signature shown separately.
  • Auto-converts iat, nbf, exp to ISO dates and flags expiry.
  • Live signature verification for HS256 / HS384 / HS512.
  • Sign new tokens with any HMAC secret — great for local testing.
  • Runs in your browser — no token or secret leaves your device.

Frequently asked questions

Is a JWT encrypted?
No. A JWT is signed, which means its authenticity is verifiable, but the header and payload are Base64URL-encoded in plain sight. Anyone can read them. For encrypted tokens, use JWE (a separate spec). Do not put passwords, API keys, or sensitive PII in a JWT payload.
What does 'Signature invalid' mean?
Either the secret is wrong, the token was tampered with, or the algorithm mismatch — our verifier supports only HS256/384/512. Confirm your secret exactly matches the issuer's and that the header's 'alg' matches the secret type.
Why is my RS256 token not verifying?
RS256 uses asymmetric keys (private to sign, public to verify). Our tool currently supports only HS* (HMAC-based). Add public-key verification is on the roadmap; in the meantime, use jwt.io or your backend's JWT library for RS/ES verification.
What are iat, nbf, and exp?
Registered JWT claims for time. iat (issued-at) is when the token was created; nbf (not-before) is the earliest moment it's valid; exp (expiry) is when it stops being valid. All are Unix epoch seconds. Our decoder converts each to a readable ISO date and flags an expired token in red.
Can I send tokens I decode to a server?
Not through this tool. Decoding happens entirely in your browser; we never see the token or the secret. If you need a server-side JWT verifier, use your backend language's JWT library (jsonwebtoken, pyjwt, jose).
What's the 'alg: none' vulnerability?
Early JWT implementations accepted tokens with 'alg: none' as valid without verifying anything. Many were exploited before libraries fixed the default. Modern libraries reject 'none' by default; always configure accepted algorithms explicitly in your verifier.