How JWT Tokens Use Base64URL Encoding
Every JSON Web Token (JWT) you've seen — in an Authorization header, a cookie, or an OAuth response — is built from three Base64URL-encoded segments. Understanding that encoding demystifies what a JWT actually is: not a black box, but readable JSON wrapped for safe transport.
The three segments
A JWT has the shape header.payload.signature, three Base64URL strings joined by dots. The header and payload each start life as a plain JSON object — for example {"alg":"HS256","typ":"JWT"} — that gets Base64URL-encoded into text. The signature is a cryptographic hash of the first two segments, also Base64URL-encoded, computed with a secret or private key.
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8UWhy Base64URL and not standard Base64?
JWTs are designed to travel inside URLs, HTTP headers and cookies without any extra escaping. Standard Base64's + and / characters (and = padding) have special meaning or awkward encoding requirements in those contexts, so the JWT spec (RFC 7519) mandates Base64URL: - and _ instead of + and /, with padding omitted entirely.
Readable, but not writable
Because Base64URL is just an encoding (see is Base64 encryption?), anyone can decode a JWT's header and payload and read the JSON inside — paste the first two segments into the Base64 decoder (with -/_ swapped back to +//) to see for yourself. What an attacker can't do is forge a new signature without the secret or private key, which is what makes a JWT tamper-evident even though its contents are fully visible.
The practical takeaway
Never put secrets, passwords, or anything sensitive directly in a JWT payload — treat it as public information. Use the signature purely to verify the token hasn't been altered or forged, and pair JWTs with TLS in transit for real confidentiality.