› JWT Decoder
Decode and inspect the header and payload of any JSON Web Token.
The Debugging Scenario That Sends Developers to a JWT Decoder
Your API returns 401 Unauthorized. The token looks valid. The frontend claims it was just issued. You suspect the token might be expired, or the aud claim is wrong, or the payload carries a role claim the backend is not seeing. To diagnose any of these, you need to read what is actually inside the token — not what you think should be there. That is the primary use case for a JWT decoder: rapid, trustworthy inspection of the three components in the compact dot-separated format that is difficult to read by eye.
A JWT has the form header.payload.signature. Each part is Base64URL-encoded (URL-safe variant of Base64 that uses - and _ instead of + and /, and omits padding). The header and payload are plain JSON; the signature is a cryptographic value computed over the first two parts. Decoding is simply Base64URL decoding — no key required. Verification is a different operation that requires the issuer's key.
The Encoding vs. Encryption Confusion
This is the most dangerous misconception about JWTs. Base64URL encoding is not encryption. It is a reversible encoding scheme that any developer, tool, or attacker can decode in milliseconds without any key. When you paste a JWT into this decoder (or into jwt.io, or into a simple base64 decoder), you get the full plaintext payload immediately.
The practical consequence: never place sensitive data in a JWT payload. User IDs, roles, session identifiers — these are fine. Passwords, API keys, personally identifiable information, financial data, medical records — these must stay server-side. The JWT signature guarantees the payload has not been modified, but offers zero protection against being read. Encrypted JWTs (JWE, RFC 7516) do offer confidentiality, but they are a different format with a different structure — this tool decodes signed JWTs (JWS) only.
Reading the Standard Claims
RFC 7519 defines a set of registered claim names that have specific semantics:
iss(issuer): a string or URI identifying who issued the token. The backend should validate this matches the expected issuer — accepting tokens from arbitrary issuers is a critical vulnerability.sub(subject): the entity the token refers to, typically a user ID.aud(audience): which service(s) the token is intended for. If your API receives a token withaud: "admin-service"but your API isuser-service, it must be rejected — even if the signature is valid. Audience confusion attacks exploit services that skip audience validation.exp(expiration): Unix timestamp (seconds since epoch) after which the token is invalid. Validate on every request, not just at login.iat(issued at): when the token was created. Useful for detecting tokens issued before a password reset or account compromise event.nbf(not before): the token is invalid before this timestamp. Less commonly used but useful for pre-issued tokens (e.g., tokens for a scheduled operation).jti(JWT ID): a unique identifier for the token. Required for revocation — without it, there is no per-token way to invalidate a specific token before expiry.
Common JWT Implementation Bugs
Understanding what is in a JWT helps identify these frequently encountered mistakes:
- Algorithm confusion (alg:none attack): old libraries accepted
"alg":"none"in the header, bypassing signature verification entirely. Always check thealgfield in the header — any production token should use RS256, ES256, or HS256; "none" should be explicitly rejected by your validation library. - Missing audience validation: a token signed by your auth server is valid — but if it was issued for a different service, accepting it is a security error. Check
aud. - Long expiry without revocation: a 30-day
expwithout a revocation mechanism means a stolen token is valid for 30 days. Design for short expiry (15–60 minutes) plus refresh token rotation. - Storing JWTs in localStorage: XSS-vulnerable. Prefer httpOnly cookies for session tokens.
How to Use This Tool
- Paste any JWT string into the input field.
- The header JSON, payload JSON, and the raw signature bytes are displayed immediately.
- The
expandiattimestamps are automatically converted to readable UTC dates. - No network request is made — decoding is pure client-side JavaScript.
## man jwt-decoder
?> Does this tool verify the JWT signature?
No. Signature verification requires the issuer's signing key — a secret (for HMAC algorithms like HS256) or a public key (for RSA/ECDSA like RS256/ES256). This tool decodes the header and payload only. For signature verification, use your backend JWT library with the appropriate key.
?> Is it safe to paste a production JWT here?
Decoding happens entirely in your browser — the token is not transmitted. However, treat production tokens as sensitive: they are live session credentials. The safer practice for debugging is to reproduce the issue with a test token, or to inspect the token in your browser's developer tools from within the authenticated session.
?> Why do some JWTs have five parts instead of three?
A five-part token is a JWE (JSON Web Encryption) token, not a JWS (signed JWT). JWE encrypts the payload so it cannot be read without the recipient's private key. The format is: protected header . encrypted key . initialization vector . ciphertext . authentication tag. This tool does not decode JWE tokens.
?> What is the alg:none vulnerability and am I at risk?
Early JWT libraries treated "alg":"none" in the header as a valid algorithm, meaning no signature was required. An attacker could forge any payload by setting alg to none and omitting the signature. All modern libraries (post-2015) explicitly reject alg:none by default. You are at risk only if you use a very old or unmaintained JWT library, or if your code explicitly passes an allowedAlgorithms list that includes "none".