Home › Guides › Base64 Is Encoding, Not Encryption

Base64 Is Encoding, Not Encryption

Base64 appears in data URIs, JWTs, email attachments, API payloads and private-key files, and it is the single most misunderstood notation in everyday programming — mostly because people see U3dvcmQ= and assume something protective happened. Nothing was protected. Base64 is a alphabet-translation step with a closed-form length formula, and you can reverse it in your head once you know the rules.

What the algorithm does

Binary data is bytes: 8 bits each. Some transport layers were built for text and mangle bytes that are not printable ASCII. Base64 fixes that by re-cutting the same bit stream into 6-bit groups, because 2^6 = 64 and 64 printable characters were chosen to be safe almost everywhere. Three bytes (24 bits) therefore become exactly four 6-bit groups, and each group indexes a 64-character alphabet. That is the entire idea; the padding character = only records that the last group was short.

The standard alphabet is A–Z, a–z, 0–9, then + and /. Index 0 is A, index 26 is a, index 52 is 0, index 62 is +, index 63 is /.

A worked example, byte by byte

Take the three characters Man. Their bytes are 77, 97, 110. Laid end to end that is 24 bits, split into four 6-bit numbers:

Byte group24-bit value6-bit indexesAlphabet characters
77, 97, 110507121419, 22, 5, 46‘T’ ‘W’ ‘F’ ‘u’

Concatenated, that is TWFu — which is exactly what Buffer.from(“Man”).toString(“base64”) returns. Nothing was hidden: the mapping is a lookup, and a lookup with a published alphabet has no key.

Why the output length is predictable

Because 3 bytes always become 4 characters, an n-byte input always produces ceil(n/3)×4 characters, with (3 − n mod 3) mod 3 padding signs. So you can tell how big the original file was from the length of the blob alone — another reason it is encoding rather than encryption:

Input bytesBase64 charactersPadding =Size increase
142300%
241100%
34033.3%
482100%
58160%
68033.3%
712271.4%
812150%
1624250%
100136236%

The asymptotic cost is 33.33% — four-thirds of the original. On a 100-byte payload the measured increase is 36% because padding lands at the end. This is why base64 is a poor choice for storing large binaries in a database column and a perfectly reasonable one inside JSON, where the alternative is worse.

The UTF-8 trap that bites everyone once

Base64 operates on bytes, so the first question is always “bytes of what?”. In JavaScript the classic pair btoa and atob is defined over Latin-1 code units, not UTF-8. Feed it anything outside that range and it refuses outright — on the runtime used for this page, btoa(“naïve café — 日本語”) throws DOMException: Invalid character.

The correct route is to convert to UTF-8 bytes first, then encode. Same string, three different answers depending on what you assumed:

InterpretationResult
JS string length (code units)16
UTF-8 byte length26
Base64 of the UTF-8 bytesbmHDr3ZlIGNhZsOpIOKAlCDml6XmnKzoqp4=
Base64 of the same string read as Latin-1bmHvdmUgY2Fm6SAUIOUsng==
Do those two match?No — this is the mojibake bug

Round-tripping the UTF-8 form returns the original string exactly (verified), which is the property you want. The encoder on this site does the UTF-8 conversion with TextEncoder and TextDecoder rather than btoa, so non-ASCII input survives the trip.

URL-safe Base64, and why the padding disappears

Two characters in the standard alphabet are hostile inside URLs: + is read as a space in query strings and / looks like a path separator. Base64url swaps them for - and _, and most implementations also drop the = padding, since the length already determines how many bytes were missing. Three bytes chosen to force both symbols, 0xfb 0xff 0xbe, encode as:

VariantOutput
Standard+/++
URL-safe-_--

This is what you are looking at in a JWT: three base64url segments separated by dots, and — this surprises people the first time — the header and payload are simply JSON, so decoding a token you were given reveals its claims immediately. A JWT’s security comes from the signature on the third segment, never from the encoding of the first two.

Where you actually meet it

So when is it not reversible?

Never, without extra machinery. If you need one-way, that is a hash — and note that a hash is not secret either, it is only irreversible in practice for a good function and a non-guessable input; a common password hashed with SHA-256 and not salted is a few seconds of GPU work. If you need confidentiality, encrypt first and encode the ciphertext afterwards, in that order. Base64’s job is to survive a text-only pipe, and it does that job well; treating it as a security layer is the mistake.

Frequently asked questions

Can I tell base64 apart from random text?

Usually yes: the alphabet is restricted, length is a multiple of four in the standard form, and ASCII text encodes with a characteristic pattern because most English letters land in the low 7 bits. Base64 of compressed or encrypted data looks uniformly random apart from the alphabet.

Why does my decoded text have = signs in it?

You probably skipped padding before decoding. Base64url drops the = characters; a decoder that expects the standard form needs them re-added to reach a multiple of four. This site’s decoder normalises - and _ and re-pads automatically.

Is base64 a compression?

It is the opposite — a ${B.asymptoticInflationPct}% expansion. Compress first if size matters, then encode.

Why do two files with the same first bytes encode identically?

Because the transform is a sliding 3-byte window with no key, no salt and no chaining. That property is also why you can spot a PNG header in a base64 blob: iVBOR is the encoding of the PNG signature.

Related tools

Base64 Encoder & Decoder

Encode and decode with the standard and URL-safe alphabets, UTF-8 correct. Free browser-based tool on this site. Runs locally, nothing is uploaded.

Number Base Converter

See the same value in binary, octal, decimal, hexadecimal and arbitrary bases — the 6-bit grouping idea at a smaller scale.

SHA Hash Generator

The one-way operation people confuse Base64 with, side by side across four algorithms.

JWT Decoder

Split a token into its three base64url segments and read the header and payload claims.

Written and maintained by CHENYUWEN. First published 2026-10-30. If something here is wrong, tell us - corrections are dated on the page.