JWT Decoder

Paste a JWT (three base64url-encoded parts separated by dots) and the decoder shows the header, payload and signature, decoded and pretty-printed, along with the detected algorithm, token expiry in your local time, and whether nbf (not-before), iat (issued-at) and exp (expiry) are consistent. Optional signature verification if you have the secret or public key.

How to decode a JWT

  1. 1

    Paste the token

    Three base64url strings separated by `.` (header.payload.signature).

  2. 2

    Read the decoded header

    Algorithm, type, key ID (`kid`). Algorithm tells you what key type you need for verification.

  3. 3

    Read the payload

    Standard claims (`iss`, `sub`, `aud`, `exp`, `iat`, `nbf`, `jti`) plus whatever custom claims your application issues.

  4. 4

    Verify (optional)

    Provide the HMAC secret (for HS256/384/512) or the public key (for RS256, ES256, etc.) to confirm the signature is valid.

Anatomy of a JWT

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNjAwMDAwMDAwfQ
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Each segment is base64url (not standard base64) encoded. The header is JSON like {"alg":"HS256","typ":"JWT"}, the payload is JSON like {"sub":"1234567890","name":"Alice","iat":1600000000}, and the signature is the HMAC or RSA signature of header.payload.

Standard claims (RFC 7519)

Claim Name Notes
iss Issuer Who minted the token
sub Subject Who the token is about
aud Audience Who the token is for
exp Expiration time Unix timestamp; rejected after this time
nbf Not before Unix timestamp; rejected before this time
iat Issued at Unix timestamp of token creation
jti JWT ID Unique identifier for revocation lists

Supported algorithms

alg value Key type
HS256/HS384/HS512 Shared HMAC secret
RS256/RS384/RS512 RSA public key
ES256/ES384 ECDSA public key
PS256/PS384 RSA-PSS public key
EdDSA / Ed25519 Edwards curve
none Never trust this, unsigned tokens

The alg: none footgun

Early JWT libraries allowed "alg": "none" tokens and naively accepted them as valid. Always:

  • Whitelist the algorithms your application accepts.
  • Reject alg: none unconditionally.
  • Reject alg: HS256 when your verification code expects RS256 (the “algorithm confusion” attack).

What JWT is NOT

  • Not encrypted. The header and payload are base64-encoded, which is trivially decoded. Never put secrets in a JWT without wrapping it in JWE.
  • Not revocable by default. Once issued, a JWT is valid until exp. For revocation you need a blacklist or short expiry + refresh tokens.
  • Not a session cookie replacement for every use case. Opaque tokens stored server-side are often simpler and safer.

Common mistakes

  • Trusting the header. The kid and alg come from the token itself. A compromised server can set them arbitrarily; always validate against a fixed list.
  • Ignoring nbf and iat skew. Clock drift means iat > now can happen. Allow a small leeway (30-60s).
  • Logging whole JWTs. The payload often contains user IDs, emails, permissions, PII that should not end up in stdout.
  • Using HS256 with a weak secret. A 16-character secret is brute-forceable in minutes. Use at least 256 bits of random entropy.

Frequently Asked Questions

No. Decoding runs in your browser. The token stays local, important because JWTs often contain session data, user IDs and permissions.

Yes. If you paste the shared HMAC secret or the PEM-encoded public key, verification happens in your browser. The key never leaves your machine.

It means the token is unsigned. Never accept such tokens in production, they can be forged trivially. Several high-profile CVEs were specifically about libraries that accepted alg: none by default.

JWT signing proves authenticity, not confidentiality. The header and payload are base64url-encoded, which is reversible. For secrecy, use JWE (JSON Web Encryption) around the JWT, or avoid putting sensitive data in the payload.

Related Tools

Tool available in other languages