Skip to content
ZeroServer.tools

JWT Decoder

Decode JSON Web Tokens instantly. Tokens are never sent to a server.

What is a JSON Web Token (JWT)?

A JWT is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature structure, enabling the claims to be digitally signed.

Why you should never use server-side JWT decoders

JWTs often contain sensitive user session data or authentication tokens. Pasting them into third-party, server-backed websites is a massive security risk. ZeroServer's JWT Decoder splits and decodes your token's Base64Url header and payload directly within your DOM, keeping your authentication data strictly on your machine.

Built and maintained by Meet Shah · Last updated

What this tool is used for

  • Reading the claims out of a token an API just rejected, to see whether the problem is the audience, the issuer, or simply the clock.
  • Checking exp and iat against the current time when a session dies earlier than expected — clock skew between two services is a common and invisible cause.
  • Confirming which scopes or roles a token actually carries, rather than the ones the login flow was supposed to grant.
  • Identifying the signing algorithm and kid in the header when rotating keys, so you can tell which key a live token was issued against.
  • Inspecting a production token safely: it never leaves the tab, so reading one does not create a copy of a live credential on somebody else's server.
  • Teaching or reviewing — showing that the payload of a JWT is signed rather than encrypted, and is readable by anyone holding the token.

How it works in practice

A worked example

An API is answering 401, and you have both the token the client sent and the signing secret from the service configuration, with no idea which of the two is at fault.

Input
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfODQxMiIsIm5hbWUiOiJEYW5hIE9rYWZvciIsInNjb3BlIjoiaW52b2ljZXM6cmVhZCIsImlhdCI6MTc4NTU3NDgwMCwiZXhwIjoxNzg1NTc1NzAwfQ.2KTlqYEXbqERouF5RkhlNv-hi2WeRTG8nflKRr8gKQY

HMAC secret:  zeroserver-demo-secret
Output
{ "alg": "HS256", "typ": "JWT" }

{
  "sub": "usr_8412",
  "name": "Dana Okafor",
  "scope": "invoices:read",
  "iat": 1785574800,
  "exp": 1785575700
}

Issued At (iat)   Sat, 01 Aug 2026 09:00:00 GMT
Expires  (exp)    Sat, 01 Aug 2026 09:15:00 GMT     Expired
Signature         Verified

The signature checks out and the token is expired, and those are two independent facts about it. HMAC-SHA256 over the first two segments with that secret reproduces the third exactly, which proves the token came from something holding the key and has not been altered since. Expiry is just a number sitting in the payload, fifteen minutes after the issue time, and comparing it against a clock is the verifier's job rather than the signature's. A signature that checks out says nothing whatsoever about whether a stale token is safe to accept.

The edge case that catches people

The algorithm name lives in the header, which means it arrives from whoever sent the token. This page reads it to preselect the dropdown, which is correct for a decoder and precisely wrong for a verifier: a service that trusts what the header claims can be handed HS256 on an endpoint built for RS256, and talked into checking the signature using its own public key as the shared secret — a key the attacker has too, because it is public. Pin the expected algorithm in the verifying code and ignore what the token asserts about itself.

When not to use this tool

A signature that checks out is still not an authorisation decision, and this page cannot make one for you. It has no idea what audience or issuer you expect, it cannot see a revocation list, and nothing tells it the session was logged out of ten minutes ago. For RS256 or ES256 you have to supply the public key yourself, which in practice means going and fetching the issuer's JWKS. And an encrypted token, five segments rather than three, has nothing here to read at all.

Frequently Asked Questions

What is a JWT?
A JSON Web Token has three parts (header.payload.signature) separated by dots. The header describes the algorithm; the payload carries claims (user id, expiry, roles); the signature proves the token hasn't been tampered with.
Is it safe to decode a JWT here?
Yes. Decoding reads the Base64URL-encoded header and payload — they contain no secret, and nothing leaves the tab. Sensitive data should never be in a JWT payload unless the whole token is JWE-encrypted. Signature checking is optional and also local: paste the secret or public key.
Why does this tool show my token as expired?
The 'exp' claim is a Unix timestamp. The tool compares it to the current time — if exp is in the past, the token has expired. Tokens typically expire in minutes to hours to limit the window of misuse.
Can I modify a JWT payload and have it accepted by a server?
No. You can decode and re-encode the payload, but the signature becomes invalid without the server's secret key. Any server that verifies signatures will reject a manually modified token.
What's the difference between HS256 and RS256?
HS256 uses a shared secret (HMAC-SHA256) — both sides know the same key. RS256 uses an RSA key pair — the server signs with a private key and verifies with a public key. RS256 is safer when multiple services need to verify tokens.
Does decoding a token verify it?
No — decoding only base64-decodes the segments, which anyone can do. Verification requires the signing key and is what actually establishes trust, so a decoded payload should never drive an authorisation decision.

Common errors and gotchas

  • Pasting a token with a trailing newline or a stray space from the copy. Base64url has no tolerance for it, and the decode fails on a token that is otherwise fine.
  • Copying only two of the three segments. A JWT is header.payload.signature, and some log formats truncate the signature — what is left still looks plausible.
  • Assuming the token is encrypted because it looks opaque. It is Base64url, not ciphertext, so never put anything in a payload you would not show the bearer.
  • Treating a successful decode as a valid token. Decoding reads the payload; it does not check the signature, and a tampered token decodes perfectly.
  • Reading exp as milliseconds. JWT timestamps are seconds since the epoch, so a naive new Date(exp) lands in January 1970 and looks like an expired token.
  • Confusing an opaque session id or an OAuth access token for a JWT. If it has no dots it is not one, and there is nothing here to decode.

Related Cryptography & Security tools

Private & free — this tool runs entirely in your browser.

IndieKitShip your Next.js startup in days.affiliate