All articles
Security August 17, 2026 4 min read

Reading a JWT Without a Library (And Why You Shouldn't Trust It)

A JWT is three Base64 chunks joined by dots. Anyone can read one — which is exactly why decoding is not verifying.

A JSON Web Token looks opaque. It isn't. It's three Base64url strings joined by dots, and two of them are plain readable JSON.

The anatomy

eyJhbGciOiJIUzI1NiJ9  .  eyJzdWIiOiIxMjMifQ  .  SflKxwRJSMeKKF2QT4f...
       header                    payload                signature

Header — the signing algorithm, e.g. {"alg":"HS256","typ":"JWT"}.

Payload — the claims: who the token is about, who issued it, when it expires.

Signature — proof that a party holding the secret produced it.

Split on the dots, Base64url-decode the first two, and you have the contents. No key required.

The claims worth knowing

ClaimMeaning
issIssuer — who created it
subSubject — who it's about
audAudience — who it's for
expExpiry, as a Unix timestamp
nbfNot valid before
iatIssued at
jtiUnique token ID

exp and iat are seconds, not milliseconds. Multiply by 1000 before handing them to a JavaScript Date, or you'll conclude every token expired in 1970.

Decoding is not verifying

This is the part that matters. Reading a JWT tells you what it claims. It tells you nothing about whether those claims are true. Only checking the signature against the issuer's key does that.

The classic vulnerability is a server that decodes a token, reads {"role":"admin"} and believes it. An attacker edits the payload, re-encodes it, and walks in. Related: the alg: none attack, where a token declares it isn't signed at all and a naive library accepts it.

Rule: never make an authorisation decision from a decoded-but-unverified token.

What decoding is genuinely useful for

  • Debugging "why am I getting a 401" — usually exp in the past or the wrong aud
  • Confirming which environment issued a token by reading iss
  • Checking that a claim your app depends on is actually present
  • Reading the expiry to size your refresh window

SwitchPDF JWT Decoder shows the header, the payload, and whether the token has expired, entirely in your browser. That last part matters: a JWT is a live credential, and pasting one into a server-side decoder means handing your session to a stranger.

Anyone holding the token can read it

Because the payload is only encoded, never put anything private in it. No email addresses, no internal IDs you'd rather not leak, no permissions detail you consider sensitive. Assume the user, their browser extensions and anyone with access to their machine can read every claim.

Bottom line

Decode freely for debugging — it's just Base64. Verify before you trust. And treat the payload as public information, because to anyone holding the token, it is.

Related articles