Tokens, cookies, and what is actually secret
Base64 is not encryption and a JWT is signed, not hidden — both are readable by anyone holding them.
Base64 is an encoding, not a secret
Base64 turns bytes into characters that survive being put in text — a URL, a header, an email. It is trivially reversible by design and provides no protection whatsoever.
Every so often a password or a key turns up base64-encoded in a config file, treated as hidden. It is not hidden; it is written in a slightly inconvenient alphabet. Anything base64 can be decoded by anyone holding it, in one step, with no key.
A JWT is signed, and that means readable
A JWT is three base64 sections: a header, a payload of claims, and a signature. The signature proves the first two were not altered by someone without the key. It does not hide them.
So a JWT payload is readable by anyone who has the token, including the browser it was issued to. Putting anything private in it — an internal id you would not publish, a role you would not admit to, anything about another person — is publishing it to whoever holds the token.
What the signature gives you is integrity: change a claim and the signature no longer matches, so a server that verifies it will refuse. A server that decodes without verifying is trusting a value anyone can edit, which is one of the most common authentication bugs there is.
Check the expiry too. A token with no exp, or one a server does not check, is valid forever — and a token stolen once is then useful forever.
Cookies and where a token should live
A cookie is sent automatically with every matching request, which is convenient and is exactly what makes CSRF possible: another site can cause a request that carries your cookie. SameSite=Lax or Strict is what stops that, and Secure keeps it to HTTPS.
HttpOnly keeps a cookie away from JavaScript, so a cross-site scripting bug cannot read it. A token in localStorage has no such protection: any script on the page can take it, including one that arrived through a bug in a dependency. That is the real trade — cookies need CSRF defences, tokens in JavaScript need you to be sure nothing hostile ever runs on the page.
Worked examples
Read a JWT payload without any key at all
/header.payload.signature/Against:
Three base64 sections separated by dotsThe first two decode in one step with no key. Anyone holding a token can read its claims — the signature stops edits, not reading.
Check yourself
Practice questions written for this lesson — not past exam papers.
Practise every question in this subject
What does the signature on a JWT give you?
Why is a token in localStorage a different risk from one in an HttpOnly cookie?