Skip to content

JWT Decoder: Read Header, Payload & Expiry Locally

JWT decoder that shows the header, payload, and exp/iat times in plain dates. Runs 100% in your browser, so your token is never uploaded or logged.

By Updated Runs in your browser

JWT Decoder guide

Paste a JSON Web Token to read its header and claims, see when it was issued and when it expires, and spot unsigned alg:none tokens. Decoding happens on your device; the token never leaves the page.

Anatomy of a JWT

A JSON Web Token is three Base64URL-encoded chunks joined by dots: header.payload.signature. The header says how the token was signed, for example {"alg": "HS256", "typ": "JWT"}. The payload holds the claims: who the user is, who issued the token, and when it expires. The signature is a cryptographic hash of the first two parts, computed with a key only the issuer (and verifier) should have.

Base64URL is ordinary Base64 with two substitutions, - for + and _ for /, and the trailing = padding removed so the token is safe in URLs and HTTP headers. That is why a JWT header almost always starts with eyJ: it is the Base64 encoding of the characters {".

How decoding works, step by step

Split the token on the dots. Take the first segment, swap - back to + and _ back to /, add = padding until the length is a multiple of 4, Base64-decode it to bytes, interpret the bytes as UTF-8, and parse the result as JSON. Repeat for the second segment. That is the entire algorithm, and it is why decoding needs no key.

Worked example: the segment eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 is 36 characters, already a multiple of 4, so no padding is needed. Decoded, it reads {"alg":"HS256","typ":"JWT"}. The sample token loaded in the tool has the payload {"sub": "1234567890", "name": "Mavis", "role": "admin", "iat": 1758764800, "exp": 2000000000}. The iat value is September 25, 2025 at 01:46:40 UTC and the exp value is May 18, 2033 at 03:33:20 UTC.

Reading the time claims

exp, iat, and nbf are NumericDate values: seconds since January 1, 1970 UTC, per RFC 7519. A common bug is treating them as milliseconds, which is what JavaScript's Date.now() returns. If a decoded expiry lands in January 1970, someone divided by 1,000 twice; if it lands tens of thousands of years in the future, someone stored milliseconds.

Access tokens are usually short-lived, often 5 to 60 minutes, and refreshed with a separate refresh token. If you see a token with no exp at all, it is valid until the signing key is rotated, which is a real security smell for anything beyond internal tooling. Servers also typically allow a small clock skew, often around 30 to 60 seconds, when checking exp and nbf.

Decoding is not verification

This is the most important thing to understand about JWTs. Anyone can create a token that says role: admin. It decodes perfectly. What makes it trustworthy is the signature, and checking that requires the key: a shared secret for HS256, or the issuer's public key for RS256 and ES256, usually published at a JWKS URL.

Verify tokens in your backend with a maintained library (jose for Node, PyJWT for Python, the official libraries for Java and Go). Pin the expected algorithm, check exp, nbf, iss, and aud, and reject alg none. RFC 8725, the JWT Best Current Practices document, lists these checks. Algorithm confusion, where an RS256 public key is misused as an HS256 secret, has caused real authentication bypasses in libraries that trusted the header's alg field.

Why a local decoder matters

A JWT is a bearer credential: whoever holds a valid one can use it. Pasting a live production token into a site that logs requests or offers save-and-share links is the same as pasting a password. In November 2025, watchTowr Labs reported collecting more than 80,000 publicly listed saved pastes from the save features of jsonformatter.org and codebeautify.org, and finding administrative JWTs alongside Active Directory credentials, cloud keys, and private keys.

This decoder runs entirely in your browser tab with atob and TextDecoder. There is no save button, no share link, and no network request carrying your token. You can load the page, go offline, and it still works.

Troubleshooting

Three parts, but the payload fails to parse: the token was probably truncated when copied from a log line. Five parts: it is a JWE, an encrypted token, and the payload is unreadable without the decryption key. One long string with no dots: it is an opaque token, common with some OAuth providers, and must be checked with the provider's introspection endpoint. The decoder strips a leading Bearer prefix for you, so you can paste an Authorization header value directly.

How we calculate: sources

Frequently asked questions

Is it safe to paste a JWT into an online decoder?

Only if the decoder runs locally. A JWT is a bearer credential: anyone holding a valid one can act as you until it expires. This page decodes with JavaScript in your browser and sends nothing to a server. In November 2025, watchTowr Labs reported finding admin JWTs among 80,000+ publicly listed pastes saved on two online code formatters, which is exactly the risk to avoid.

Does it verify the signature?

No. Verification needs the issuer's secret (HS256) or public key (RS256, ES256), and should happen in your backend with a maintained library. Decoding only reads the claims, and anyone can forge a token that decodes fine.

How do I check if a JWT is expired?

Look at the exp claim, a Unix timestamp in seconds. The decoder converts it to your local time and tells you whether it has passed. exp 2000000000, for example, is May 18, 2033 at 03:33:20 UTC.

Is a JWT encrypted?

A standard signed JWT (JWS) is not. The header and payload are just Base64URL-encoded JSON, readable by anyone. Never put passwords or sensitive personal data in a JWT payload. Encrypted tokens (JWE) have 5 parts instead of 3.

What do iat, exp, nbf, sub, iss, and aud mean?

They are registered claims from RFC 7519: iat is issued-at, exp is expiration, nbf is not-before, sub is the subject (usually a user ID), iss is the issuer, and aud is the intended audience.

What is the alg none attack?

A token with "alg": "none" has no signature. Some old libraries accepted these, letting attackers forge any payload. RFC 8725 says servers must reject unexpected algorithms. The decoder flags alg none in amber.

Why does my token fail to decode?

Common causes: a truncated copy, a stray quote or space, or it is not a JWT at all (opaque tokens from some OAuth providers are random strings). A valid JWT has exactly three dot-separated Base64URL segments.

Is my data uploaded?

Everything runs in your browser. Nothing you enter is uploaded to a server or stored by us.

Where should I store JWTs in a web app?

For browser apps, an HttpOnly, Secure, SameSite cookie keeps the token out of reach of JavaScript and XSS. localStorage is simpler but readable by any script on the page. Keep access tokens short-lived either way.

Can I revoke a JWT?

Not directly. A signed JWT stays valid until exp. To revoke early, keep a server-side denylist of token IDs (the jti claim), rotate the signing key, or use short expiries with refresh tokens you can revoke.