Free tool JWT decoder: read the claims, then verify the signature
Paste a JSON Web Token to see its header and claims, with exp, iat and nbf turned into dates in your time zone. Add the secret or public key and the signature is checked in your browser. Decoding alone proves nothing about who issued the token; the page says so every time.
- Decode and verify
- Expiry in local time
- Token and key stay local
Decode and verify a JWT
The sample token was issued at 01:00 UTC on 10 November 2026 and expired an hour later, so it shows as expired. Click "Fill in the sample secret" to verify it, or try the RS256 sample with its public key.
The whole token. A Bearer prefix, quotes and line breaks are removed.
HS256/384/512: the shared secret. RS, PS, ES, EdDSA: a PEM public key, an X.509 certificate, a JWK or a JWKS. Never paste a private key here or anywhere else.
Checks
Expiry, algorithm, signature and common risks.
- NoteSigned with HS256 (HMAC).
- ErrorExpired 2 days ago (exp 2026-11-10 02:00:00). A server will reject it.
- NoteLifetime from iat to exp: 1 hour.
- NoteTimes shown in UTC.
- NoteDecoded only, not verified. Anyone can create a token with these claims; only the signature check proves who issued it. Add the secret or public key above.
{
"alg": "HS256",
"typ": "JWT"
}Which algorithm signed the token, and which key (kid).
{
"iss": "https://auth.example.com",
"sub": "u_10086",
"aud": "api.example.com",
"iat": 1794272400,
"exp": 1794276000,
"scope": "read:reports",
"name": "Alex Chen"
}Readable by anyone who holds the token.
DQC0OLmWDRWbX96S2oepGFxFe6fdW6xLyLCe2BDVZ48
hex (32 bytes):
0d00b438b9960d159b5fde92da87a9185c457ba7dd5bac4bc8b09ed810d5678fBase64URL as in the token, and the raw bytes in hex.
Claims explained
Registered claims first (RFC 7519 §4.1). Times are shown in your browser’s time zone.
| Claim | Value | Meaning | Status |
|---|---|---|---|
iss | https://auth.example.com | Issuer: who created and signed the token | — |
sub | u_10086 | Subject: usually the user ID | — |
aud | api.example.com | Audience: who the token is meant for | — |
exp | 1794276000 → 2026-11-10 02:00:00 (2 days ago) | Expiration time | Expired |
iat | 1794272400 → 2026-11-10 01:00:00 (2 days ago) | Issued at | — |
scope | read:reports | Permissions granted (space-separated) | — |
name | Alex Chen | Display name (personal data) | — |
Version v1.0Updated Update history
Three parts, one rule
A JWT is header.payload.signature, each part Base64URL-encoded. The first two are just JSON; the third is what makes the token trustworthy.
Header
alg names the signing algorithm, typ the token type and kid which key to use. A server should decide the algorithm itself rather than trust this field blindly.
Payload
The claims: who the token is about (sub), who issued it (iss), who it is for (aud) and when it expires (exp). It is encoded, not encrypted.
Signature
Computed over the first two parts with a secret (HS) or private key (RS, PS, ES, EdDSA). Change one character of the payload and the signature no longer matches.
Decoded is not verified
Anyone can write a token with any claims. Until the signature checks out against the issuer’s key, and exp, aud and iss are what you expect, treat the content as untrusted input.
This page verifies with the browser’s Web Crypto API. The token and key are not sent anywhere, but treat production tokens like passwords: prefer a test token, and revoke one you have pasted somewhere you do not control.
Three steps
Decode first, verify second.
-
1
Paste the token
Straight from an Authorization header or a cookie. Header, payload and claim table appear at once.
-
2
Read the checks
Expired, not yet valid, missing exp, alg none, personal data in the payload: each is listed with a plain explanation.
-
3
Add the key to verify
Paste the shared secret for HS tokens, or the issuer’s public key, certificate or JWKS for RS, PS, ES and EdDSA. The result replaces "Checking the signature…".
Registered claims and how they are checked
RFC 7519 §4.1 registers seven claim names. All are optional, but servers that issue tokens almost always set iss, sub, exp and iat. Times are NumericDate: whole seconds since 1970-01-01 UTC.
- Signing input is
BASE64URL(header) + "." + BASE64URL(payload), with no padding (RFC 7515 §7.1) - HS256 uses HMAC-SHA256 with a key of at least 32 bytes; RS256 RSASSA-PKCS1-v1_5; PS256 RSA-PSS; ES256 ECDSA P-256 with a 64-byte signature (RFC 7518 §3)
- Servers should pin the expected algorithm and reject
none(RFC 8725) - A five-part token is an encrypted JWE; its claims can only be read with the recipient’s private key
| Claim | Name | Type | What a server checks |
|---|---|---|---|
iss | Issuer | String or URL | Equals the issuer you trust |
sub | Subject | String | Who the token is about, often the user ID |
aud | Audience | String or array | Contains your service’s identifier |
exp | Expiration | Seconds since 1970 | Now is before exp (with small clock leeway) |
nbf | Not before | Seconds since 1970 | Now is at or after nbf |
iat | Issued at | Seconds since 1970 | Not in the future; used for token age |
jti | JWT ID | String | Not seen before, if you block replays |
The sample token, taken apart
The default token on this page, decoded part by part. Its signature was made with Node.js crypto.createHmac and checks out with the sample secret.
| Part | Starts with | Decoded | Takeaway |
|---|---|---|---|
| Header | eyJhbGciOiJIUzI1NiIs… | {"alg":"HS256","typ":"JWT"} | HMAC-SHA256 with a shared secret |
| Payload | eyJpc3MiOiJodHRwczov… | "sub":"u_10086", "iat":1794272400, "exp":1794276000 | Issued 2026-11-10 01:00 UTC, valid for one hour |
| Signature | DQC0OLmWDRWbX96S… | 32 bytes | Matches only with the sample secret |
| Verdict | — | Signature valid, token expired | A server would reject it with a 401 |
Change one letter in the payload and paste it back: the claims still decode, but the signature check fails. That is the whole point of the signature, and why decoding alone is not enough.
Where JWT handling goes wrong
Most JWT incidents are not broken crypto but skipped checks.
Decoding instead of verifying
Reading sub or role from a token without checking the signature lets anyone forge their way in. Always verify, then check exp, aud and iss.
Trusting the alg header
Accepting none, or verifying an RS256 token with HMAC using the public key as the secret, are classic forgeries. Pin the algorithm per key (RFC 8725).
Secrets in the payload
The payload is only Base64URL. Email addresses, phone numbers and internal IDs in it are readable by anyone who sees the token, including in logs and browser storage.
Milliseconds in exp
exp is in seconds. Writing Date.now() produces a token that is valid for thousands of years in most libraries.
Identify users by ID, not by token
After sign-in, your app knows who the user is, usually from the token’s sub. That ID is what analytics needs, never the token itself.
Call login with your user ID
In identified mode, call tapcub.login(id) after sign-in with a stable internal ID. The device’s earlier anonymous visits are backfilled to the person.
Placeholders are rejected
IDs such as "guest", "0", "null" or "anonymous", and IDs over 200 characters, are not accepted, so one bad call cannot merge every visitor into one person.
Learn moreKeep tokens out of events
Event properties are stored as you send them. Send the user ID and business fields, never a JWT, a session cookie or the email claim.
Learn moreJWT questions
Still have a question?
Chat with the team behind TapCub — we usually reply within a few hours on business days.
How do I decode a JWT?
Paste it into the box. The header and payload are Base64URL-encoded JSON, so they decode instantly; the claims table explains each field and turns exp, iat and nbf into dates in your time zone. No key is needed to decode.
Is it safe to paste a JWT into an online decoder?
On this page the token is decoded and verified in your browser; nothing is uploaded, and the token and key are never put in a link. Still, a live token works like a password until it expires, so prefer test tokens, and revoke any production token you have pasted into a site you do not control.
Does decoding a JWT verify it?
No. Decoding only reads the Base64URL text, and anyone can produce a token with any claims. Verification checks the signature with the issuer’s secret or public key, and then exp, nbf, aud and iss. Until then, the claims are untrusted.
How do I verify a JWT signature?
Paste the key in the second box. HS256, HS384 and HS512 need the shared secret (tick Base64 if it was issued that way). RS, PS, ES and EdDSA tokens need the public key as PEM, an X.509 certificate, a JWK, or a JWKS from which the key with the matching kid is picked.
Why does it say "invalid signature" when the secret is right?
Common causes: the secret was issued as Base64 and must be decoded first; a space or line break crept into the secret; the token was re-encoded or cut while copying; or the server signs with a different key than you think (check kid). An RS256 token never verifies with an HMAC secret.
What is the difference between JWT, JWS and JWE?
A JWT is a set of claims. Almost every JWT you see is a JWS, signed with three parts that anyone can read. A JWE has five parts and an encrypted payload that only the recipient can read. This tool decodes and verifies JWS tokens.
Why is my token expired when it was just issued?
Usually clocks: the server that checks is behind or ahead of the issuer, or exp was written in milliseconds or in local time instead of seconds since 1970 UTC. Compare exp and iat in the claims table.
Update history
New features, fixes and data refreshes for this tool, newest first.
-
· v1.0
LaunchedFirst release.
Missing something or found an error? Tell us — requests that come up often go into the next update. All tool updates
Connect sign-ins to behaviour
Identify signed-in users with your own ID, and see each person’s journey across devices and visits.