A JWT payload is readable by anyone holding the token
A JSON Web Token arrives looking like a long opaque credential, and it gets treated like one: something the server understands and the client cannot. Half of that is true. The client cannot forge it. The client can read every character of it.
The three parts
A JWT is three chunks separated by dots: header, payload, signature. The header and payload are JSON objects, Base64url-encoded. Base64url is ordinary Base64 with two characters swapped for URL-safe ones and the trailing padding usually dropped, so the token survives being put in a URL or a header.
Decoding those chunks needs no key, because Base64url is an encoding, not a cipher. The first chunk of the sample token on the tool page is eyJhbGciOiJIUzI1NiJ9, and decoded it reads {"alg":"HS256"}. The second chunk is eyJ1c2VyIjoiZ2ciLCJhZG1pbiI6dHJ1ZX0, which reads {"user":"gg","admin":true}.
That is the entire trick. There is no step you skipped and no protection you got past.
Anything you put in a JWT payload, you have published to whoever holds the token. The browser holds it. Whatever the browser stored it in holds it. Anything with access to the machine holds it.
What the signature actually does
The third chunk is a signature over the first two. It answers exactly one question: has this token been changed since it was issued? Flip admin from false to true and the payload no longer matches the signature, so a server that checks properly rejects it.
Note what that does not include. It does not make the contents private. It does not stop the token being copied and replayed by whoever obtained it. And it only means anything to somebody who verifies it — with the right key, and with the algorithm the server decided on rather than the one the token asks for, since the alg field lives in the token and is therefore an input, not an authority.
So: what does not belong in a payload
The test is simple. Would you be content for the payload to be printed out and handed to the person holding the token, and to anyone that person shows it to? If not, it does not go in.
That rules out more than people expect. Personal details beyond what the holder already knows about themselves. Internal identifiers, table keys and system names that describe how your backend is laid out. Anything about other people. Anything about a customer that the person carrying the token is not entitled to know. A payload is a public statement with a tamper-evident seal on it — useful, but public.
And what not to trust
Decoding is not verifying. Reading a token tells you what it says, and a token can say anything at all, because anyone can write one and Base64url-encode it. The claims only become worth acting on after the signature has been checked against the key, along with the issuer, the audience and the expiry.
The expiry deserves its own sentence, because it is the one people mentally promote. An expiry claim is a number in the payload. Unverified, it is a suggestion. Nothing about a token enforces its own expiry — the code that checks it does that, and only when the check is actually run.
The other half of not trusting a token is not leaking one. A JWT in hand is usually enough to act as the user until it expires, so pasting a live token into a web page, a chat, an issue tracker or a log is handing over the credential itself. If you are debugging with a real token, treat it the way you would treat the password: use one that is short-lived, and retire it afterwards.
The tool
The JWT Decode tool splits the token on the dots and Base64url-decodes the header and payload so you can read the claims. It does that locally, in your browser, and the token is not uploaded. It also does not verify the signature, and it says so — a decoded token can still be a forged token. It is there for reading, and reading is the part anybody can do.