skip to content

Token Structure

Three Base64url segments joined by dots — JOSE header, claims payload, signature — and how a compact token is assembled and taken apart. A warm-up that catches anyone who thinks a JWT is encrypted.

part ofFederated identityoverview, primer and where to startread it →
on this pageshow

questions

5

Why can anyone read a signed JWT's payload, and what does that mean for what you put in it?

level: juniorimportance: must knowfreq 78%

answer

  1. Encoding versus encryption
  2. A seal, not an envelope
  3. The client holds the token
  4. Readable by all, trusted until verified
  5. Logs see what the header carries

basics

~20 s

Base64url is an encoding, not encryption, and a signature protects integrity rather than confidentiality. Anyone holding a signed JWT can decode its claims, so it must carry no secrets and no data the holder should not see.

solid answer

~40 s

The middle segment of a signed JWT is just the claims JSON run through Base64url, which is a reversible text transformation with no key involved. Any browser console, proxy log viewer or online decoder turns it straight back into readable JSON. The signature adds **integrity and authenticity** — you can tell nobody altered the claims and that the expected issuer produced them — but it adds nothing to confidentiality. So the payload is visible to the client that holds the token, to anything that logs the header it travels in, and to any intermediary that sees it. The practical rule: put in identifiers and coarse claims the holder is already entitled to know, and keep passwords, keys, full personal records and internal flags you would not show the user out of it entirely.

code

javascript · 4 lines
javascript
// no key, no library, no privileges required
const token = localStorage.getItem('access_token');
const payload = JSON.parse(atob(token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/')));
console.log(payload); // { iss: "...", sub: "user-42", role: "admin", ... }

go deeper

for a junior

Recall the one-liner: Base64url is reversible with no key, so the payload is public. Be able to say what you would and would not place in a claim.

for a middle

Distinguish integrity and authenticity from confidentiality precisely, and explain why TLS does not change what the token discloses once it is stored or logged.

for a senior

Show you review token contents as a disclosure surface — what reaches client storage and log stores — and that you redact whole token values rather than individual claims.

for a principal

Own the policy: what may ever enter a token, how services get the rest, and how token size and claim sprawl couple teams together as the payload becomes an informal shared schema.

## Encoding is not encryption Base64url takes arbitrary bytes and represents them using 64 characters that survive URLs, headers and cookies unharmed. It is a *representation* change, deterministic and public: no key participates, so reversing it needs nothing but the algorithm. Encryption transforms data so that only a holder of the key can recover it. Confusing the two is the single most common JWT misconception, and it produces real incidents — access tokens carrying internal user records, tokens with an embedded API key, tokens whose claims reveal a pricing tier or a fraud score the user was never meant to see. ## What the signature actually buys The third segment is computed over the first two using a key. Verifying it tells you two things: the claims are exactly as the issuer wrote them (integrity), and they were written by a party holding the signing key (authenticity). It tells you nothing about who has *seen* them. A signature is a tamper-evident seal, not an envelope. This is why "it's signed, so it's safe" is not an answer to "is this data exposed?". ## Who can read it in practice - **The client.** In a browser or mobile app the token lives on the user's device; the user can decode it at leisure. - **Anything on the path that logs.** Tokens ride in `Authorization` headers, sometimes in query strings; proxies, gateways and APM tools capture them, and payload contents land in log stores with a different access policy than your database. - **Anyone who obtains the token later.** Stolen tokens leak their contents immediately, before any question of whether they still verify. TLS protects the token in transit, but it protects nothing at the endpoints or in logs, and it is not a property of the token format. ## What belongs in the payload A useful test: *would you be comfortable showing this claim to the person the token was issued to?* If not, it does not belong there. Identifiers, an issuer, an audience, expiry, a coarse role set — fine. Passwords, secrets and API keys, full addresses and national identifiers, internal risk scores, other users' data, internal hostnames or database ids you rely on staying obscure — not fine. Note that this is a *disclosure* judgment, not a size judgment; the fact that a claim is small does not make it safe. ## A related trap: trusting decoded claims The mirror-image mistake is reading claims without verifying the signature. Because decoding is trivial, it is trivially easy to write code that parses the payload and acts on it — a gateway that reads `role` to route a request, a debug tool that becomes production code. Anyone can craft a token with any claims they like; only signature verification makes them meaningful. Decode-only handling and "the payload is private" are two halves of the same misunderstanding: the payload is *readable by everyone and trustworthy to no one* until verified. ## Practical mitigations Keep tokens small and claim-poor: carry a subject identifier and let services look up what they need behind their own authorization checks. If a claim really must be confidential end-to-end, the answer is a token format that encrypts, or simply not putting it in a token — never Base64 tricks, never "nobody will look", never obfuscated field names. And treat tokens themselves as secrets in your logging pipeline: redact the whole `Authorization` value rather than trying to scrub individual claims.

  • Doesn't TLS make the payload confidential?
    Only while the token is on the wire. The token still sits in the client's storage, in server logs, in proxy traces and in anything that captures headers. Confidentiality of the token's *contents* is a property of the token format and of what you chose to put in it, not of the transport.
  • If claims are readable, why sign them at all?
    So they cannot be changed. Without a signature any holder could rewrite `sub` or a role claim and be believed. Signing binds the claims to an issuer and makes tampering detectable — which is precisely the property a stateless verifier needs, and it is independent of who can read them.
  • Is it safe to read a claim before verifying the signature?
    Only for routing hints you would accept from an anonymous caller, such as reading `kid` to pick a key. Never for an authorization decision: unverified claims are attacker-controlled input, and code that acts on a decoded-but-unverified payload is trivially bypassed by handcrafting a token.

saying these in an interview costs you the question

  • Says a JWT is encrypted so the payload is safe
  • Thinks the secret key hides the claims
  • Calls Base64 a form of encryption
  • Stores passwords or API keys in claims because it is signed
  • Believes only the server can decode the token

context

open as a page

What are the three dot-separated parts of a JWT, and what does each contain?

level: juniorimportance: must knowfreq 88%

basics

~10 s

A signed JWT is three Base64url segments joined by dots: a JOSE header naming the algorithm and key, a JSON claims payload, and a signature computed over the first two segments.

open as a page

Why does a JWT use Base64url encoding rather than standard Base64, and why is padding dropped?

level: middleimportance: should knowfreq 45%

basics

~20 s

Standard Base64 uses '+', '/' and '=', which need escaping in URLs, query strings and some headers. Base64url substitutes '-' and '_' and JOSE omits the '=' padding, so a token is safe to place anywhere unescaped.

open as a page

Besides alg, what fields can appear in a JWT's JOSE header, and what does typ mean?

level: middleimportance: should knowfreq 42%

basics

~20 s

Common JOSE header fields are typ (the token's media type), cty (content type, set to JWT for a nested token), kid (which key was used) and crit (extensions a verifier must understand). All are metadata about the cryptography, not application claims.

open as a page

A gateway decodes a JWT, re-serializes its JSON and forwards it; verification now fails. Why?

level: seniorimportance: should knowfreq 40%

basics

~20 s

A JWS signature covers the exact encoded bytes of the header and payload segments joined by a dot, not the abstract JSON. Re-serializing changes whitespace, key order or escaping, so the signing input differs and verification fails.

open as a page