🎫 JWT Token Decoder

Last updated: June 21, 2026

🎫 JWT Token Decoder

Paste your token below β€” everything runs locally in your browser. Nothing leaves your device.

JSON Web Tokens are everywhere. They secure REST APIs, authenticate single-page applications, carry OAuth 2.0 access grants, and shuttle identity claims across microservices at millions of requests per second. But for all their ubiquity, JWTs are remarkably opaque at a glance β€” a dot-delimited wall of Base64url text that tells you nothing until you actually crack it open. Knowing how to read a token is not just a debugging convenience; it is a prerequisite for reasoning correctly about your authentication layer.

The Three-Part Structure You Actually Need to Understand

A JWT is three Base64url-encoded segments joined by literal period characters. The format is header.payload.signature, and each segment has a distinct purpose that shapes how you should think about the token's security properties.

The header is a small JSON object that declares the token type and the cryptographic algorithm used to produce the signature. A typical header looks like {"alg":"HS256","typ":"JWT"}. More complex tokens add a kid (key ID) field so the verifying party knows which of several possible keys to use β€” a pattern common in multi-tenant identity providers and JWKS-backed systems. The alg field matters enormously from a security standpoint, which is why decoders surface it prominently.

The payload carries claims β€” assertions about the subject, its permissions, and the token's validity window. Claims come in three flavors. Registered claims are a set of standardized shorthand names defined in RFC 7519: iss (issuer), sub (subject), aud (audience), exp (expiration time), nbf (not before), iat (issued at), and jti (JWT ID). Public claims are collision-resistant names intended for broad interoperability. Private claims are anything an application defines for its own internal use β€” roles, feature flags, tenant IDs, plan tiers, whatever the application cares about.

The signature is what separates a JWT from a plain JSON envelope. For symmetric algorithms like HS256, it is an HMAC computed over base64url(header) + "." + base64url(payload) using a shared secret. For asymmetric algorithms like RS256 or ES256, the issuer signs with a private key and recipients verify with the corresponding public key. The signature ensures the token has not been tampered with in transit β€” but it says nothing about whether the claims are true or whether the token has been revoked. Those are validation concerns, and they are entirely separate from decoding.

The alg=none Vulnerability That Still Breaks Things in 2024

One of the more alarming chapters in JWT's history is the alg:none attack. Early JWT libraries trusted the algorithm specified in the header when verifying signatures. An attacker who obtained a valid token could change "alg":"HS256" to "alg":"none", strip the signature segment (leaving the trailing dot), and some libraries would accept the result as cryptographically valid β€” because "no algorithm" means no signature check is needed. The library was doing exactly what the spec said; the flaw was in trusting the header blindly.

Modern libraries reject alg:none by default and require callers to explicitly allowlist acceptable algorithms. But the lesson generalizes: never let the token tell you how to verify itself. Allowlist the algorithms your application expects and reject anything else. When you decode a token and see alg:none in the header, it should be treated as a red flag, not a valid identity assertion.

Reading Timestamp Claims Correctly

Timestamp claims in JWTs β€” exp, nbf, and iat β€” are stored as NumericDate values: seconds since the Unix epoch (January 1, 1970, 00:00:00 UTC). This is not milliseconds. A common mistake is feeding these numbers directly into JavaScript's new Date() constructor, which expects milliseconds, producing dates 1000x further in the future than intended. The correct conversion is new Date(claimValue * 1000).

The exp claim defines the moment after which the token must be considered invalid. RFC 7519 specifies that verifiers should allow a small clock skew β€” typically up to a few minutes β€” to account for legitimate timing differences between issuer and verifier clocks. The nbf claim works in the opposite direction: it specifies the earliest time at which the token becomes valid. This is useful for tokens issued in advance that should not be usable immediately, like a link embedded in a scheduled email.

The iat claim records when the token was minted. It is informational rather than security-critical in most implementations, but some systems use it to enforce maximum token age separately from the exp claim β€” for example, requiring that access tokens be no more than one hour old regardless of what exp says.

Symmetric vs. Asymmetric: Choosing the Right Algorithm Family

The choice between HMAC-based algorithms (HS256, HS384, HS512) and public-key algorithms (RS256, ES256, PS256, EdDSA) has architectural implications beyond raw security. Symmetric algorithms use a single shared secret for both signing and verification. This means any service that needs to verify tokens also needs access to the secret β€” which creates key distribution problems at scale. If you have five microservices all verifying JWTs, all five need the secret, and a compromise of any one of them exposes the key that can forge tokens for everything.

Asymmetric algorithms solve this by splitting the key. The issuer keeps the private key and uses it to sign. Everyone else uses the public key β€” which can be published openly via a JWKS endpoint β€” to verify. A compromised verifier cannot forge tokens because it never had the signing key. This is why identity providers like Auth0, Okta, and AWS Cognito default to RS256 and publish their public keys at well-known JWKS URLs.

ES256 (ECDSA with P-256) produces significantly shorter signatures than RS256 while maintaining comparable security. EdDSA (Ed25519) is faster still and avoids some of the pitfalls of ECDSA implementation (particularly the requirement for a secure random nonce β€” a constraint that famously caused the PlayStation 3 signing key compromise). If you are building a new system with algorithm flexibility, EdDSA is worth considering.

What Decoding Cannot Tell You

Decoding a JWT reveals its claims and algorithm, but it cannot answer several questions that matter operationally. It cannot tell you whether the signature is valid β€” you need the secret or public key for that. It cannot tell you whether the token has been revoked β€” you need to consult a revocation list, blacklist, or check token family state. And it cannot tell you whether the claims are true β€” an issuer could put false information in the payload and the token would decode and verify just fine.

This distinction becomes critical when debugging authentication failures. A token might decode perfectly β€” correct-looking claims, non-expired timestamp, valid algorithm β€” and still be rejected by your server. The rejection could be a signature mismatch (wrong issuer key), audience validation failure (aud does not match the server's expected audience), or a revocation check. Decoding gives you the starting point for that investigation, not the final answer.

The Payload is Not Encrypted β€” Act Accordingly

JWT payloads are encoded, not encrypted. Base64url is trivially reversible by anyone who holds the token. This means anything you put in the payload is readable to the token bearer and to anyone who intercepts the token in transit. Do not store sensitive data β€” passwords, credit card numbers, SSNs, PII beyond what is strictly necessary β€” in a standard JWT payload.

If you need encrypted tokens, the spec covers that too: JWE (JSON Web Encryption) wraps the payload in an encrypted envelope. JWE tokens look similar to JWT at a glance but have five segments rather than three. Decoding them requires the decryption key. For most applications, TLS in transit combined with careful claim minimization is sufficient β€” put an opaque user ID in sub and look up sensitive attributes in your database when needed, rather than materializing everything into the token.

Understanding what you are looking at when you decode a JWT β€” the algorithm choice, the claim semantics, the timestamp arithmetic, the distinction between decoding and verification β€” transforms a token from an opaque black box into a readable, auditable security artifact. That clarity is worth developing deliberately rather than stumbling through when something breaks at 2am.

FAQ

Is it safe to paste my real JWT into this decoder?
Yes β€” this tool runs entirely in your browser using JavaScript. Your token is never sent to any server, logged, or stored anywhere. You can verify this by disconnecting from the internet before pasting; the decoder will still work perfectly because all computation happens locally.
Why does the decoder say 'EXPIRED' when I just got the token?
The exp claim is a Unix timestamp in seconds, and expiry is evaluated against your device's current clock. If your system clock is significantly ahead of the issuing server's clock, a token that the server considers valid may appear expired to this decoder. Check your system time. Also note that some access tokens are intentionally short-lived (minutes, not hours) β€” an expired token is not always a bug.
Can this tool verify the JWT signature?
No, and that is intentional. Verifying a signature requires the secret (for HS256/384/512) or the public key (for RS256, ES256, etc.). Sending those to a third-party tool would defeat the purpose of asymmetric cryptography or expose your shared secret. Signature verification must happen in your application code using a trusted JWT library. This tool focuses on decoding and inspecting the plaintext claims.
What is the difference between a JWT and a JWE?
A standard JWT has three Base64url segments and an encoded (but not encrypted) payload β€” anyone with the token can read the claims. A JWE (JSON Web Encryption) token has five segments and an encrypted payload that only the holder of the decryption key can read. JWEs are used when the claims themselves are sensitive. This decoder handles standard JWTs (three-part tokens); JWE decryption requires the private key and is intentionally out of scope.
Why does alg='none' trigger a security warning?
A token with alg=none has no cryptographic signature β€” anyone can craft one with arbitrary claims. Early JWT libraries had a vulnerability where they respected this header value and skipped signature verification entirely, allowing attackers to forge tokens. Modern libraries reject alg=none by default, but the decoder flags it as a reminder that such a token must never be accepted as a trusted identity assertion.
What do iss, sub, aud, iat, nbf, exp, and jti actually mean?
These are the seven registered claims defined in RFC 7519. iss (issuer) identifies who created the token. sub (subject) identifies who the token is about β€” typically a user ID. aud (audience) specifies the intended recipients. iat (issued at), nbf (not before), and exp (expiration) are Unix timestamps marking when the token was created, when it becomes valid, and when it expires. jti (JWT ID) is a unique identifier for the token, used to prevent replay attacks by tracking which token IDs have already been used.