My Tool Studio
Developer Tools·4 min read

How to Decode a JWT: Header, Payload, and Expiry

Knowing how to decode a JWT turns a mysterious 401 into a five-second diagnosis. A JSON Web Token looks like random text, but it's really two base64url-encoded JSON documents and a signature, joined by dots. Decode it and you can read exactly what your auth server put inside: who the token belongs to, when it was issued, and, most usefully, when it expires. This guide walks through the token structure, a worked example you can paste straight into the JWT Decoder, and the habits that make token debugging quick.

Hello WorldSGVsbG8gV29ybGQ=Encoded

The 401 that wasn't a permissions problem

Where decoding earns its keep.

Picture a staging environment where every request suddenly gets rejected. The frontend team suspects CORS, the backend team suspects the gateway, and someone starts reading nginx configs. The actual cause, found twenty minutes later, was a token issued with a one-hour lifetime by a login flow nobody had re-run since the previous afternoon. One decode would have shown the exp claim sitting in the past.

This pattern repeats constantly. Auth failures rarely announce their reason, because servers deliberately keep 401 responses vague. The token itself is far more talkative. Every claim your identity provider set is sitting in the payload, readable by anyone who splits the string on its dots.

How to decode a JWT in three steps

A JWT has three segments separated by periods: header, payload, and signature. The first two are base64url-encoded JSON, which means reading them requires no keys and no secrets. Split the string on the dots, decode each of the first two segments, and pretty-print the result.

The JWT Decoder does all of that live as you paste. It splits the token, decodes the header and payload, renders both as formatted JSON with copy buttons, and if it finds an exp claim it converts the timestamp to a date and warns you when that moment has already passed.

JWT header payload signature explained

The header is small, usually two fields. alg names the signing algorithm, such as HS256 or RS256, and typ identifies the token type. If alg ever says none, be suspicious, because unsigned tokens are a classic attack vector.

The payload carries the claims. Registered ones include sub for the subject, iat for issued-at, and exp for expiry, all expressed as epoch seconds. Custom claims like roles or tenant IDs sit alongside them. The signature, the third segment, is a cryptographic seal over the first two parts. Decoding never touches it, and reading a token tells you nothing about whether its signature is genuine.

A worked example you can paste in

Take this header segment: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. Decoded, it reads {"alg":"HS256","typ":"JWT"}. Now a payload segment: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkFkYSIsImlhdCI6MTcxOTkxMjM0NSwiZXhwIjoxNzUxNDQzMjAwfQ decodes to {"sub":"1234567890","name":"Ada","iat":1719912345,"exp":1751443200}.

Those two timestamps are the interesting part. 1719912345 is 2024-07-02T09:25:45Z, the moment of issue. 1751443200 is 2025-07-02T08:00:00Z, the expiry. Join the two segments with a dot, paste them into the decoder, and you'll see the same JSON plus an expiry warning, since that second date is now behind us.

Is it safe to paste tokens online?

It depends entirely on where the decoding happens. A site that posts your token to its server for processing now holds a live credential, and you should assume it gets logged somewhere. That's a genuine risk with production tokens, which behave exactly like temporary passwords.

This decoder runs fully client-side. The JavaScript splits and decodes the token inside your browser, and no network request ever carries it. Even so, a sensible habit is to debug with short-lived staging tokens, and to revoke any production token that has ended up in chat logs or ticket systems.

Token mistakes that keep the 401 alive

A few missteps account for most wasted hours around JSON Web Tokens:

  • Checking everything except exp. Expired tokens are the single most common cause of sudden 401s, and the decoder flags them automatically.
  • Reading exp as milliseconds. JWT timestamps are epoch seconds, so treating 1751443200 as milliseconds lands you in January 1970.
  • Trusting decoded claims as verified. Anyone can forge a payload; only signature verification with the correct key proves authenticity.
  • Pasting a truncated token. Logging pipelines love cutting long strings, and a missing chunk breaks base64url decoding.
  • Confusing the access token with the ID token. OAuth flows often issue both, and their payloads answer different questions.

Two habits that speed up token debugging

First, decode before you debug anything else. It costs ten seconds and rules out the whole class of expiry and audience problems before you touch a server log. Compare exp against the current epoch, and confirm that aud and iss match what your API validates.

Second, keep a known-good token around. When requests start failing, decode the working token and the failing one side by side. The claim that differs is usually your answer, whether it's a missing role, the wrong tenant, or a clock-skewed iat.

When you need a different tool than a token viewer

Not every encoded string is a JWT. If you're holding a plain base64 value, a cookie, or an encoded config blob, the Base64 Encoder / Decoder handles it without expecting three dot-separated segments.

And when all you have is a lone numeric claim, say an exp value copied from a log line, the Unix Timestamp Converter turns it into a readable date in one paste. For anything shaped like header.payload.signature, the decoder remains the faster path.

Try it now

Open JWT Decoder

The tool is one click away. No sign up, no upload, no payment.

Open JWT Decoder