Part of: Browser-Based Developer Tools: Why Client-Side Beats Uploading

Base64 Encoding Explained (and the Mistake Everyone Makes)

Three bytes of binary data being regrouped into four Base64 characters

Base64 turns up everywhere: JWTs, data URIs, email attachments, Kubernetes secrets, API credentials. It is also the encoding developers most consistently misunderstand — usually in the same specific way, which we will get to.

What it actually does

Base64 represents arbitrary binary data using only 64 printable ASCII characters: A–Z, a–z, 0–9, + and /.

The mechanism is simple regrouping. Binary data is a stream of 8-bit bytes. Base64 ignores the byte boundaries and re-slices the same bits into 6-bit groups, because 2⁶ = 64 and each group therefore maps to exactly one character in the alphabet.

Three bytes (24 bits) become four characters (4 × 6 = 24 bits). When the input does not divide evenly by three, the remainder is padded and = characters mark how much padding was added — which is why encoded strings so often end in = or ==.

That regrouping is the whole algorithm. Nothing is compressed, nothing is transformed, nothing is protected.

Why it makes things bigger

Every three bytes in becomes four characters out. That is a 4/3 ratio: Base64 output is about 33% larger than its input, before padding.

This is the cost of the guarantee it provides. It matters when you inline an image as a data URI — a 90 KB PNG becomes roughly 120 KB of markup, and unlike the original file it cannot be cached separately from the document that contains it.

The mistake everyone makes

Base64 is not encryption, and it is not obfuscation. It is an encoding, and it is trivially reversible by anyone, with no key.

This sounds obvious written down. It is nonetheless the single most common Base64 error in production systems, and it shows up as:

  • Kubernetes secrets described as “encrypted” because the YAML is Base64. It is not encrypted. base64 -d reads it.
  • Credentials Base64-encoded in a config file to keep them “out of plain sight”. They are in plain sight.
  • A JWT treated as opaque or tamper-proof. The header and payload of a JWT are Base64URL, readable by anyone holding the token. Only the signature provides integrity, and it proves the token was not modified — not that its contents are private. Never put anything in a JWT payload you would not hand to the bearer.

If you need secrecy, encrypt. Base64 is for making binary data survive a text-only channel, and that is all it is for.

Standard vs URL-safe

Two characters in the standard alphabet cause trouble in URLs. + means a space in query strings, and / is a path separator. A standard Base64 string dropped into a URL can therefore arrive corrupted.

Base64URL solves this by substituting - for + and _ for /, and usually dropping the = padding since the length implies it. This is the variant JWTs use, which is why a JWT contains - and _ but never + or /.

A decoder expecting the standard alphabet will fail or produce garbage on Base64URL input. If a decode is failing for no apparent reason, this is the first thing to check — see why JSON URLs contain backslashes for a closely related class of “the string is fine, the escaping is not” bug.

Where you will legitimately meet it

  • Data URIsdata:image/png;base64,... inlines a small asset and removes one HTTP request. Worth it for icons, rarely worth it above a few kilobytes.
  • HTTP Basic authAuthorization: Basic <base64 of user:pass>. Note that this is exactly the “encoding is not encryption” case: Basic auth is only safe over TLS.
  • Email attachments — MIME has used it since 1992 to move binary files through a channel designed for 7-bit text.
  • JWTs — three Base64URL segments joined by dots.

Decoding it safely

Base64 payloads frequently contain credentials, tokens or personal data, which makes where you decode them a real decision rather than a detail. Pasting a production JWT into an unknown web page hands its contents to whoever runs that page.

The Base64 Encode / Decode and JWT Decoder tools here run entirely in your browser — nothing is transmitted. The reasoning behind that choice, and how to verify it for any tool rather than taking a claim on faith, is in browser-based developer tools.

The short version

Base64 makes binary safe for text channels at a 33% size cost. It provides no secrecy whatsoever. Use Base64URL anywhere the result touches a URL. And decode sensitive tokens locally.

← All articles