belun.app Blog
RU

How to Decode a JWT (and What Every Claim Actually Means)

A practical guide to JSON Web Tokens — the three parts, the standard claims, and how to read a token safely without leaking it.

Developer inspecting a JSON Web Token on a laptop while debugging a login flow

The first time a login bug lands on your desk, you usually end up staring at a long string that starts with eyJ. That’s a JSON Web Token, and the fastest way to figure out why a request is getting rejected is to read what’s actually inside it. Paste it into the JWT Decoder and you’ll see the header and payload in plain JSON, no command line required.

The three parts, separated by dots

A JWT is just three Base64URL strings glued together with periods: header.payload.signature.

The header is small — usually two fields. alg says how the token was signed (HS256 and RS256 are the common ones), and typ is almost always JWT. The payload is where the interesting stuff lives: who the token is for, when it was issued, when it expires. The signature is the part that proves nobody edited the first two pieces after they were signed.

Here’s the thing people miss: the header and payload aren’t encrypted. They’re encoded. Base64URL is reversible by anyone — that’s why a decoder can show you everything without a key. If you’ve ever pasted a JWT into a chat to ask a teammate “why is this failing,” you’ve handed them every claim in it.

Reading the standard claims

The JWT spec (RFC 7519) defines a handful of registered claims with short, cryptic names. They show up constantly, so it’s worth knowing them cold:

  • iss — issuer. Who minted the token.
  • sub — subject. Usually the user ID.
  • aud — audience. Which service the token is meant for.
  • exp — expiry, as a Unix timestamp.
  • iat — issued-at, also a Unix timestamp.
  • nbf — not-before. The token is invalid until this time.

The three timestamps trip people up because 1719230400 doesn’t mean anything at a glance. The decoder converts those to readable UTC dates for you, so you can tell whether exp is five minutes from now or five months ago.

That exp value is the claim you’ll check most. If the current time is past it, the token is dead and the server rejects it — which explains a huge share of “it worked yesterday” tickets. When clocks drift between two servers, you can even get a token that one machine thinks is valid and another thinks expired.

Decoding is not verifying

This is the part worth being loud about. Reading a token tells you what it claims. It does not tell you whether those claims are true.

Verification means recomputing the signature with the secret (for HMAC) or the public key (for RSA and ECDSA) and checking it matches. That has to happen on your server, with a key the browser never sees. A client-side decoder like ours deliberately stops at decoding — it shows you the signature segment but won’t pretend to validate it.

There’s history here. Some early JWT libraries would honor an alg: none header and skip signature checks entirely, which let attackers forge tokens by just deleting the signature. Modern libraries refuse that, but it’s a good reminder: never trust a payload you decoded in a browser as proof of anything.

Keep the token on your machine

Plenty of online JWT decoders POST your token to their backend. That’s a problem when the token is a live session for a real user — you’ve now leaked working credentials to a third party.

The JWT Decoder runs the whole thing in JavaScript on your page. Nothing is uploaded. You can pull your network cable after the page loads and it still decodes. For tokens out of staging or production, that’s not a nice-to-have — it’s the only safe way to inspect them.

Paste a token, read the claims, check the expiry, move on with your day.

Try the tool

JWT Decoder →