How to Decode a JWT: Header, Payload, Signature and the Expiry Check

Your login worked, the API returned a token, and now something is failing with an unhelpful "unauthorised" โ€” and the only clue is a long string of characters separated by two dots. That string is a JSON Web Token, and it is not opaque: it is two readable JSON documents and a signature, and decoding it takes seconds once you know what to look at. Our free JWT decoder does exactly that. Paste any token and see precisely what is inside โ€” header, payload and signature โ€” decoded instantly, with standard claims like exp, iat and nbf translated into readable dates and a warning when a token is expired. It runs 100% client-side: your token never leaves your browser. This guide explains how to use it, how decoding actually works, the classic example token worked step by step, and the mistakes that make developers misread their own tokens.

How to Use the JWT Decoder

1. Paste the token into the box. It decodes automatically as you type โ€” no need to press anything โ€” or hit Decode Token to force a fresh decode. 2. Check the badges first. The blue badge shows the signing algorithm (alg), and the green or red badge tells you at a glance whether the token is still valid or EXPIRED, with the remaining lifetime spelled out. 3. Read the claims table. exp, iat and nbf are translated from Unix timestamps into both UTC and your local time, so "is this token supposed to work right now?" is answered immediately. 4. Inspect the header and payload JSON. The pretty-printed output shows every claim โ€” user id, roles, issuer, audience โ€” exactly as your backend will see it. Spot a missing exp? That is a token that never expires, which is worth knowing. 5. Remember the privacy guarantee. Everything happens in this page. You can even disconnect your network and keep decoding โ€” the ultimate proof that your token never leaves your device. One practical note: copying tokens out of terminal output is the usual source of "invalid token" errors, because terminals love to add line breaks and trailing spaces. The decoder trims whitespace automatically, but a token split across two lines will still need to be joined first.

How JWT Decoding Works

A JWT is not encrypted โ€” it is merely encoded. Decoding reverses three simple steps. A token has three parts separated by dots: header, payload and signature. Each of the first two parts is JSON text run through base64url encoding โ€” standard base64 with + and / swapped for - and _ and the = padding stripped, so the token survives inside URLs and HTTP headers. The decoder splits on the dots, reverses the base64url step, and parses the JSON. The third part, the signature, is left untouched: it is a cryptographic checksum that only the issuer's key can verify, and a decoder has no business touching it. That distinction is the whole security story of JWTs in one paragraph. Decoding tells you what a token claims. It does not tell you whether the claim is true โ€” only signature verification, with the issuer's key, does that, and a decoder that cannot see the key cannot do it. The timestamp claims are Unix times โ€” seconds since January 1, 1970. The decoder multiplies by 1,000 to get JavaScript milliseconds and formats the result twice: once in UTC (the lingua franca of servers and logs) and once in your local timezone (the time on your wrist). Comparing exp against the current time produces the validity badge: red EXPIRED if the moment has passed, green with a countdown like "expires in 2d 4h 12m" if it has not.

Worked Example: The Classic Token

Here is the classic example token, decoded step by step. Paste it into the tool to follow along: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c. Step one: split on dots. Three parts are present โ€” header, payload, signature โ€” so the token is structurally complete. Step two: decode the header. Base64url back to JSON gives {"alg":"HS256","typ":"JWT"}: the token is signed with HMAC-SHA256 and declares itself a JWT. Step three: decode the payload. Base64url back to JSON gives {"sub":"1234567890","name":"John Doe","iat":1516239022}: the subject is user 1234567890, the name is John Doe, and the issued-at time is 1516239022. Step four: translate iat. 1516239022 seconds after the Unix epoch is January 18, 2018 (UTC) โ€” the day this example token was, in fiction, issued. Step five: check exp. There is none. This token has no expiry claim at all, which means it never expires on time grounds: a server that accepts it will accept it forever unless it checks something else, like a revocation list. That missing claim is the most instructive part of the whole example. Most real debugging sessions end at exactly this step, staring at a claim that should be there and is not.

Standard Claims: The Ones That Decide Whether a Token Works

Four claims do most of the practical work, and the decoder's claims table is built around them. exp (expiration time) is the Unix timestamp after which the token must not be accepted; the decoder's red EXPIRED badge is simply exp compared with now. iat (issued at) is when the token was created, useful for spotting clock problems and ancient tokens. nbf (not before) is the time before which the token must not be accepted โ€” a token from the future, usually a clock-skew symptom, fails here even though it has not expired. sub (subject) is who the token is about, typically a user id. Around those sit iss (issuer, who created the token), aud (audience, who it is intended for), and the application claims your backend actually authorises on: user id, roles, permissions, tenant. Read them in that order when debugging. First, is the token structurally complete โ€” three parts? Second, do exp, iat and nbf make sense against the current time in both UTC and local time? Third, does the payload contain what your backend expects โ€” the right subject, the right roles, the right audience? Most "unauthorised" mysteries resolve at one of those three gates, and the decoder shows all three without you writing a single line of throwaway code. A missing exp deserves special attention every time: it is not an error, it is a design choice by whoever issued the token, and it is a choice you should notice before you ship.

Common Mistakes

Thinking a JWT is encrypted. It is not. Base64url is an encoding, not encryption: anyone who has the token can decode the header and payload in seconds, which is exactly what this tool does. Never put passwords, secrets or sensitive personal data in a payload. Trusting a decoded payload without verifying the signature. Decoding shows what a token claims; only the issuer's key can show whether the claim is genuine. A token with a forged payload decodes just as cleanly as a real one, and a decoder cannot tell the difference. Ignoring a missing exp. A token without exp never expires on time grounds. If your system issues such tokens, every leaked token is a permanent credential until you add revocation. Copying tokens with line breaks. Terminal output wraps long tokens, and a token pasted with a newline in the middle is a different, invalid string. Join the lines first; the decoder trims surrounding whitespace but cannot repair a split token. Confusing local time with UTC. A token that "should" be valid can look expired if you compare a UTC timestamp against a local clock, or vice versa. The decoder shows both precisely so this confusion has nowhere to hide. Debugging with a production token on an untrusted site. This decoder is client-side and never sends your token anywhere, which is why it is safe for real tokens โ€” but the same cannot be said of every decoder on the web, and a token pasted into a server-side decoder is a token handed to a stranger.

Limits Worth Knowing

This decoder reads tokens; it does not judge them. It cannot verify a signature, because verification needs the issuer's secret or public key, which the decoder neither has nor asks for โ€” a decoded token that looks perfect may still be rejected by your server, and that rejection is the server doing its job. The expiry badge is about time only: a token can be unexpired and still invalid (bad signature, wrong audience, revoked server-side), and a token can be expired and still decode perfectly, because decoding is not acceptance. Clock differences matter too: if the issuing server and your machine disagree about the time, exp comparisons shift by the same amount, which is why the decoder shows both UTC and local time rather than a single verdict. And the tool decodes one token at a time, in your browser, with nothing stored โ€” there is no history, no saved token list, and no account to recover one from, which is a privacy feature, not a missing feature. Within those limits, it replaces the usual debugging ritual โ€” a throwaway script, a base64 command, a mental timestamp conversion โ€” with a paste and a glance. That is everything a JWT decoder needs to do, and it is why the first habit to build is the simplest one: before you blame the backend, decode the token. The companion guides for the same workflow are our Base64 guide, which explains the encoding underneath every token, our JSON formatting guide, for reading the decoded claims cleanly, and our URL encoding guide, for the tokens that travel inside links and redirects.

Frequently Asked Questions

Is a JWT encrypted?
No. A JWT is merely encoded, not encrypted: the header and payload are base64url-encoded JSON, and anyone with the token can decode them in seconds. Only the signature is a cryptographic value, and it proves authenticity โ€” it does not hide the contents. Never put passwords, secrets or sensitive personal data in a token payload.
Why does my token fail to decode?
The usual cause is copying: terminal output wraps long tokens and adds line breaks or trailing spaces, and a token split across two lines is a different, invalid string. Join the lines first. This decoder trims surrounding whitespace automatically, but it cannot repair a token that was pasted in pieces.
What does exp mean, and what if my token is expired?
exp is the expiration time as a Unix timestamp: the moment after which the token must not be accepted. This decoder compares exp with the current time and shows a red EXPIRED badge when the moment has passed, or a green countdown while the token is still valid. A token with no exp claim never expires on time grounds.
Can this tool verify my token's signature?
No. Signature verification needs the issuer's secret or public key, which this decoder neither has nor asks for. It decodes the header and payload and checks the time claims; whether the signature is genuine is a question only the issuing server can answer.
Is it safe to paste a real token into this decoder?
Yes, for this decoder specifically: everything runs 100% client-side in your browser, your token never leaves your device, and you can disconnect your network and keep decoding. The same is not true of every decoder on the web โ€” a server-side decoder receives your token, so prefer a client-side tool like this one for real tokens.

More guides from ToolNest

How to Encode and Decode Base64: Text, Files and the Padding Rule

The encoding underneath every token โ€” what it is, and what it is not.

How to Format JSON: Validate, Pretty-Print and Find the Error

Read the decoded claims cleanly โ€” validate and pretty-print the JSON.

How to Encode a URL: encodeURI vs encodeURIComponent, Explained With One Example

For the tokens that travel inside links, redirects and query strings.