JWT Decoder
Paste a token and get the answer you actually came for: whether it has expired, what is readable inside it, and whether the header is set up in a way somebody could abuse. Nothing is uploaded, and this jwt decoder never asks for your signing secret.
Free · No signup · Nothing leaves your browser
Decodes a JWT in your browser and tells you the part you came for: whether it has expired, what is readable inside it, and whether the header is set up in a way somebody could abuse. The token is never sent anywhere, and you are never asked for your signing secret.
Expired
Expires 2025-08-12 13:00:00 UTC · issued for a lifetime of 1 hour. Issued by Auth0. Signed with HS256 — the signature is shown but not checked, because checking it needs the key.
4 things worth knowing
- infoSigned with HS256 — a shared secret
HMAC means every service that verifies this token also holds the key to mint one. If more than one service verifies it, consider RS256 so only the issuer can sign.
- dangerExpired 370.2 days ago
Any correct verifier rejects this now. If the token was working a moment ago, this is the answer.
- warn2 claims carrying personal data
email, name. A JWT payload is base64, not encryption — it is readable by the browser, by every proxy on the path and by anything that logs the header. Signing protects it from being changed, not from being read.
- infoNo audience claim
Without aud, a token minted for one service is structurally valid at any other service that trusts the same issuer.
What the claims mean
iss"https://tekk-demo.eu.auth0.com/"Issuer — who minted the token. The verifier should check this, and a mismatch here is a common cause of a token that "should work".sub"auth0|6612f0c1a9e4"Subject — the user or service the token is about. Usually the stable user ID, not the email.email (custom)"ada@example.com"Not a registered claim. Applications add their own; the verifier has to be told to care about them.name (custom)"Ada Lovelace"Not a registered claim. Applications add their own; the verifier has to be told to care about them.roles (custom)["admin","billing"]Not a registered claim. Applications add their own; the verifier has to be told to care about them.iat2025-08-12 12:00:00 UTCIssued at.exp2025-08-12 13:00:00 UTCExpiry. After this instant the token must be rejected.
Everything runs in your browser — the token is never uploaded, logged or stored, and there is no box asking for your signing secret. A JWT from a real session is a live credential for as long as it is valid; treat pasting one into any website the way you would treat pasting a password.
Tekk is a spec-driven development platform for people building software with AI coding agents — for when the auth flow is right and the integration around it is not.
A JWT is signed, not encrypted
The payload is base64url. That is not a weak form of encryption — it is not encryption at all. It is an encoding, reversible by anyone, in one line:
JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')))
The signature stops the payload being changed without detection. It does nothing to stop it being read. Every party that handles the token can see everything in it: the user's own browser, every proxy on the path, your CDN, and anything that logs an Authorization header — which is most things, by default.
So a JWT is the wrong place for an email address, a phone number, a date of birth or a salary band. This page lists claims whose names look like personal data for exactly that reason.
Why the token is being rejected
Almost every trip to a decoder starts with a 401 that should not be happening. In roughly the order these actually occur:
| Cause | What you see |
|---|---|
| Expired | exp is in the past. Obvious once you convert the epoch — which is why it is converted for you here. |
| Clock skew | nbf or iat is in the future relative to the verifier. The token is genuinely new and genuinely refused. Intermittent, and maddening, because it depends which server issued it. |
| Wrong audience | aud names a different service. Structurally valid, correctly signed, still refused. |
| Wrong issuer | iss does not match what the verifier pinned — usually a staging token against production. |
| Wrong token type | An ID token sent where an access token was expected. They look identical. Cognito's token_use claim exists solely to tell them apart. |
| Truncated | Copied out of a log that wrapped, so the signature lost its tail. Decodes fine, verifies never. |
The header is a security surface
The JOSE header is not metadata. It contains instructions the verifier may act on, and three of them are worth checking every time:
alg: none— the token is unsigned. A library that trusts the header instead of pinning the expected algorithm will accept a payload anyone edited. This is CVE-2015-9235, it is a decade old, and it still appears.jku/x5u— a URL the verifier should fetch the key from. Without an allowlist, whoever controls the token controls the key.jwk— the key, embedded in the token that the key is meant to authenticate. Circular by construction.
None of these are exotic. They are all standard JOSE parameters from RFC 7515, and each is only a vulnerability when the verifying side takes the token's word for something.
HS256 versus RS256
HMAC means the same secret signs and verifies. Every service that can check a token can also mint one, so a shared secret distributed to five services is five places an attacker can forge from.
RSA and ECDSA split that: the issuer signs with a private key, everyone else verifies with the public one. If more than one service verifies your tokens, that asymmetry is the point.
The attack in between is algorithm confusion — take an RS256 token, change the header to HS256, and sign it with the issuer's public key as the HMAC secret. A verifier that reads the algorithm from the token and passes the public key in as "the key" will accept it.
What this page will not do
It will not verify the signature, and it will never ask for your key.
For HS256, verification needs your signing secret. A decoder that asks you to paste one into a web form is requesting a credential that mints tokens for your entire system, in exchange for confirming a signature your own backend already checks on every single request. That is not a good trade, and the habit is worse than the individual instance.
Everything above — expiry, skew, audience, issuer, header settings, what is readable in the payload — can be established from the token alone.
How it works
- 1
Paste the token, Bearer prefix and all
It decodes as you type. If what you pasted is not a JWT, this jwt decoder says what it is instead — a JWE, an opaque session ID, an API key, or a token that lost its last segment on the way out of a log.
- 2
Read the expiry line first
Expired forty seconds ago, not valid for another two minutes because of clock skew, or no exp claim at all. This is the answer to most of the questions that bring people to a jwt debugger, so it is the first thing on the page rather than a number you have to convert yourself.
- 3
Then read the findings
alg set to none, a header pointing at an attacker-controllable key URL, a lifetime measured in months, or an email address sitting in a payload that anyone holding the token can read. Each one says why it matters rather than just naming it.
Frequently asked questions
- Do you store or send my token anywhere?
- No. The decoder is a few kilobytes of JavaScript that runs on your machine — there is no server call, nothing is logged and there is no account. This matters more here than on most pages: a JWT from a live session is a working credential until it expires, so pasting one into a website is closer to pasting a password than to pasting a config file.
- Why does this not verify the signature?
- Because verifying it means handing over the key. For HS256 that is your signing secret, and a jwt validator that asks you to paste a production signing secret into a text box on the internet is asking for something worse than the problem it solves. For RS256 you would need the issuer's public key, which tells you the token was signed by whoever holds the private key — something your own backend already checks on every request. Everything this page reports can be established without either.
- Is the payload encrypted?
- No, and this is the single most common misunderstanding about JWTs. The payload is base64url, not encryption — a signature stops it being changed, not read. Anyone holding the token can see every claim, including your users, any proxy on the path, and anything that logs an Authorization header. So this jwt decoder lists any claim whose name suggests personal data, because that data is effectively public to everyone the token touches.
- My token is valid but the API rejects it. What now?
- In the order they actually happen: the token expired between issuing and use; nbf is in the future because the issuing server's clock is ahead of the verifier's; the aud claim names a different service; the iss does not match what the verifier expects; or it is an ID token being sent where an access token was expected. The panel shows all five, which is why it is more useful as a jwt debugger than a plain decode.
- What does alg: none mean?
- That the token is unsigned. A library that reads the algorithm out of the token rather than pinning the one it expects will happily accept a payload anyone edited — the attack described in CVE-2015-9235, which still ships in real code. It is flagged as a danger for that reason. If you see it on a token from a production system, the token is not the problem.
- Why does it warn about jku and x5u in the header?
- Those header parameters tell the verifier where to fetch the key. If the verifier follows the URL without an allowlist, whoever controls the token controls the key, and therefore controls the signature. A jwk in the header is the same problem in a shorter loop: the token supplies the key used to check the token.
- What is the difference between an ID token and an access token?
- An ID token describes who the user is and is meant for your application. An access token authorises a call and is meant for an API. They look identical, which is why sending the wrong one is such a common bug — Cognito's token_use claim exists precisely to tell them apart, and a jwt validator on the API side should be checking it.
- Can it tell me which provider issued the token?
- Yes, from the iss claim. Auth0, AWS Cognito, Firebase, Keycloak, Okta, Supabase, Microsoft Entra ID, Clerk, Stytch and WorkOS are recognised by their issuer URLs. It is a small thing, but useful when a token has arrived from a system you did not set up.
- Does it work as a jwt token decoder for tokens from a header or a log line?
- Yes. A leading Bearer is stripped automatically, and surrounding whitespace is ignored. As a jwt token decoder it also handles base64url properly — the dash and underscore characters that appear in most real signatures, and that decoders built on plain base64 quietly fail on.
- Why does it warn about the token size?
- Because browsers cap a single cookie at about 4 KB, and several proxies and servers cap request headers by default too. A token that grows past that limit starts failing in ways that look like an auth bug and are not. Large role or permission arrays are almost always the cause.
- Why does it warn about long lifetimes?
- A bearer token is valid until it expires, and nothing checks back with the issuer in between. That means a leaked token with a thirty-day lifetime is a thirty-day problem unless you maintain a denylist. Short access tokens plus a refresh token exist to make the window small.
- What if I paste something that is not a JWT?
- You get told what it is. Five segments means a JWE, which is encrypted and cannot be read without the key. A single opaque string is a session ID rather than a token with anything inside it. Two segments usually means the signature was truncated on copy. "Invalid token" would send you hunting for a typo that is not there.
- Is there a jwt token decoder for expired tokens?
- This one. Expiry is a claim inside the payload, not a property of the encoding, so an expired token decodes exactly like a valid one — the difference is only that a verifier will refuse it. Being able to read an expired token is usually the whole point of opening a decoder.
- Why is this free, and what is Tekk?
- Tekk is a spec-driven development platform for people building software with AI coding agents. This page costs nothing to run because nothing runs on our servers, so there is no signup wall, no run limit and no upsell inside the tool.
Want a real spec for what you’re building?
Drop a sentence. Tekk grounds it in your actual code and turns it into an executable plan.
Free to try · Connect GitHub during signup