Micro Tool Yard logo
Tools

Blog

Base64 Isn't Encryption — What It's Actually For

Why Base64 encoding looks secret but isn't, what it's genuinely useful for, and the size cost it always carries.

Paste a password into a Base64 encoder and the output looks satisfyingly scrambled —cGFzc3dvcmQxMjM= instead of password123. It's tempting to read that as "encrypted." It isn't. Base64 is a reversible, publicly documented mapping between bytes and a 64-character alphabet, with no key, no secret, and no security property whatsoever. Anyone can decode it in one line of code in any language, including by pasting it into the nearest decoder. Understanding what Base64 actually does — and why it exists at all — explains both why it keeps showing up everywhere and why relying on it for secrecy is a mistake people make more often than they'd like to admit.

The problem Base64 was built to solve

Computers store data as arbitrary bytes — any of 256 possible values per byte, including plenty that don't correspond to a printable character. Email, older HTTP headers, URLs, and plenty of text-based protocols were designed around the assumption that the content flowing through them is text: printable ASCII, no null bytes, no control characters that might get misinterpreted or stripped by something in the pipe. Attaching a JPEG to an email or embedding a font inside a CSS file means shoving binary data through a channel that expects text. Base64 is the standard answer: it takes arbitrary binary input and re-expresses it using only 64 safe, printable characters (A–Z, a–z, 0–9, plus + and/, with = as padding), so the result survives being copied, mailed, or embedded without anything along the way choking on an unexpected byte.

Mechanically, it works by grouping input bytes into chunks of three (24 bits), then re-slicing those 24 bits into four 6-bit groups. Since 6 bits gives you 64 possible values, each group maps directly onto one character of the Base64 alphabet. Three arbitrary bytes in, four safe characters out — a completely deterministic, lossless transformation. Nothing about that process involves a key, a secret, or a computationally hard operation. It's a change of representation, not a transformation of meaning, in the same way that writing "254" instead of "11111110" doesn't add any protection to the number — it's the same value in a different notation.

Where the confusion comes from

Base64 output has the visual texture of ciphertext: no spaces, mixed case, no obvious structure. That resemblance is exactly why it gets mistaken for security. HTTP Basic Authentication is a classic offender — the Authorization header sendsusername:password Base64-encoded, and it's common to see that misread as the credentials being protected in transit. They aren't; the encoding is there purely so the colon-separated text survives as an HTTP header value. Basic Auth is only safe to use over HTTPS, where the actual encryption is happening at the transport layer, not in the encoding. Strip away the TLS and the Base64 layer offers a would-be eavesdropper approximately zero extra work. The same misunderstanding shows up in JWTs: the header and payload segments of a JSON Web Token are Base64URL-encoded, not encrypted, so anyone holding a JWT can read its claims directly — the token's integrity comes from a separate signature, not from the encoding hiding anything.

A useful mental test: if decoding something requires no secret at all — no password, no key, nothing known only to the intended recipient — then whatever protection you're imagining isn't there. Base64 fails that test by design, because being universally and effortlessly reversible is the entire point. It's meant to be opened by anyone, not just an intended recipient.

What it's genuinely good for

Data URIs are probably the cleanest legitimate use case: embedding a small image directly inside HTML or CSS as data:image/png;base64,iVBORw0KG... avoids a separate HTTP request for a tiny icon, at the cost of inflating that image's size in the surrounding document. Email attachments still rely on Base64 (specifically via MIME) to carry binary files through a transport format built for text. APIs that need to transmit binary blobs — a file upload, a cryptographic signature, an image thumbnail — inside a JSON payload lean on it too, since JSON strings can't contain raw binary. In every one of these cases, the goal is compatibility with a text-only channel, never confidentiality.

The overhead nobody mentions

That three-bytes-in, four-characters-out ratio means Base64-encoded data is always about 33% larger than the original binary — every 3 bytes become 4 characters, a flat 4/3 expansion, occasionally nudged up further by padding at the end. For a small icon or a short auth token that overhead is irrelevant. For embedding a large file inline — a sizeable video thumbnail baked into a data URI, or a big attachment jammed into a JSON body — that 33% isn't a rounding error, it's real bandwidth and storage cost, and it compounds if the encoded result then gets gzip-compressed alongside already-compressed binary data (which barely shrinks further, since Base64 characters look close to random to a general-purpose compressor). Knowing that overhead exists is often the deciding factor in whether to inline an asset as a data URI or just reference it with a normal URL and let the browser fetch it separately.

None of this makes Base64 a bad tool — it solves a real, narrow problem (binary data through a text-only pipe) extremely well, and it's cheap to compute in either direction, which is exactly what a Base64 encoder/decoderis for: quickly checking what a token, header, or data URI actually contains, or producing one from raw text. The mistake is expecting it to do a second job — hiding information — that it was never designed for and doesn't attempt.