You've got a JWT and you need to see what's inside it — which user it's for, what scopes it carries, when it expires. The quick move is to search "jwt decoder," grab the first result, and paste your token in. Don't. A JWT is often a live credential, and decoding one is so simple you never need to hand it to a stranger's server. Here's how it actually works.
A JWT is just three Base64 strings
A JSON Web Token is three Base64-encoded parts joined by dots:
header.payload.signature
-
Header — how the token is signed (e.g.
HS256). - Payload — the claims: the actual data (user id, scopes, expiry).
- Signature — a cryptographic seal proving the token wasn't tampered with.
The first two parts aren't encrypted. They're just Base64URL — encoding, not secrecy.
Decode it yourself in the console
Because the header and payload are plain Base64, you can read them with nothing but the browser:
function decodeJwt(token) {
const part = (seg) =>
JSON.parse(
decodeURIComponent(
atob(seg.replace(/-/g, "+").replace(/_/g, "/"))
.split("")
.map((c) => "%" + c.charCodeAt(0).toString(16).padStart(2, "0"))
.join("")
)
);
const [header, payload] = token.split(".");
return { header: part(header), payload: part(payload) };
}
decodeJwt(myToken);
// { header: { alg: "HS256", typ: "JWT" },
// payload: { sub: "1234567890", name: "Jane Doe", exp: 1716242622 } }
No library, no network request. The token never leaves the page.
Decoding is not verifying
This is the part people miss. Anyone can decode a JWT — but that doesn't prove it's real. The signature is what proves authenticity, and checking it requires the secret or public key that signed it. HS256, for example, is HMAC with SHA-256.
So: decoding shows you the contents; verifying proves you can trust them. Never trust an unverified token server-side just because the payload looks right.
The payload is not secret
Since the payload is only Base64, whoever holds the token can read every claim in it. Don't put anything sensitive — passwords, internal flags you don't want the user to see — inside a JWT payload.
Reading the expiry
The exp, iat, and nbf claims are Unix timestamps. 1716242622 means nothing at a glance — convert it to a real date to see whether the token is still valid.
So why not just use a random decoder site?
Because a live JWT is a bearer token — practically a password until it expires. Many online decoders send what you paste to their backend, where it can be logged. If that token is still valid, you've just handed someone a working session. Decode it locally instead.
That's exactly why I built ToolNimbus JWT Decoder — it decodes the header, payload, and claims entirely in your browser, converts the expiry to a readable date, and flags whether the token is still valid. Open your network tab while you use it: nothing gets sent.
- JWT Decoder — decode header, payload & claims client-side
- Base64 Encoder / Decoder — the encoding each JWT part uses
-
Hash Generator — the SHA family behind
HS256
How do you inspect tokens while debugging — console, an extension, or a decoder? Curious what people reach for.

Top comments (0)