Base64 is not encryption
· 4 min read
Base64 output looks scrambled, which is exactly the problem: it looks like it is hiding something. It is not. It is a transport format, and treating it as a security control is a recurring source of real vulnerabilities.
What Base64 actually does
Base64 maps arbitrary bytes onto 64 characters that survive systems which only handle text. It takes three bytes at a time, splits those 24 bits into four six-bit groups, and looks each one up in a fixed alphabet. That is the entire algorithm.
There is no key. Anyone can reverse it, and the transformation costs about 33% more bytes than the input. Encoding is a format conversion; encryption requires a secret. Confusing the two is how "we obfuscated the credentials" ends up in a code review.
Where it earns its place
Base64 exists because plenty of channels are not binary-safe. Email attachments are the original case: SMTP was specified for 7-bit text, so MIME encodes binary parts. Data URIs embed an image directly in a stylesheet or an HTML document. HTTP Basic authentication encodes the credential pair so a colon in a password does not break parsing.
JWTs use the URL-safe variant, which swaps + and / for - and _ so the value survives inside a URL. Every one of these is a transport concern. None of them is a confidentiality claim — Basic auth in particular is secure only because TLS wraps it, not because of the encoding.
Padding, alphabets, and the bits people trip over
Because the algorithm works in three-byte groups, an input whose length is not a multiple of three has to be padded. That is what the trailing = signs are: one for a remainder of two bytes, two for a remainder of one. Some parsers accept unpadded input and some reject it, which is a common source of "it works in curl but not in the client".
There is also more than one alphabet. Standard Base64 uses + and /, which both have meaning inside a URL, so the URL-safe variant substitutes - and _. Mixing them up produces a string that decodes without error but yields the wrong bytes — a particularly annoying bug because nothing throws. If you are decoding a JWT segment, you want the URL-safe alphabet.
And Base64 is not Base64url is not Base32 is not hex. They are different alphabets for the same job, with different size overheads: hex doubles the input, Base32 adds 60%, Base64 adds 33%. Pick based on what the channel tolerates, not on which looks most scrambled.
The failure modes
Three keep recurring. Storing a Base64-encoded password in a config file and calling it protected — it is plaintext with extra steps, and any reviewer with a decoder can read it in seconds. Base64-encoding a payload to get it past a filter, which is why naive input validation is bypassed so easily; if your WAF rule matches on a literal string, encoding defeats it without any cleverness. And encoding large binaries into JSON, paying the 33% overhead plus the parse cost, when a separate binary channel would do.
The tell for all three is the same: someone reached for Base64 to change who could read something. It cannot do that. It changes what can carry something.
What to use when you need real protection
For data at rest, use authenticated encryption: AES-GCM or ChaCha20-Poly1305, with the key held somewhere that is not the repository. For passwords specifically, do not encrypt at all — hash with Argon2id or bcrypt, which are designed to be slow. For data in transit, TLS. For integrity without confidentiality, an HMAC or a signature.
Base64 often still appears alongside these, wrapping the ciphertext or the signature so it can travel as text. That is the correct relationship: encode after you encrypt, never instead.
Frequently asked questions
- Is Base64 reversible?
- Completely, by anyone, with no key. That is what makes it an encoding rather than a cipher.
- Why does Base64 make data bigger?
- Every three bytes become four characters, so output is about 33% larger than input, plus padding.
- What is URL-safe Base64?
- A variant that replaces + and / with - and _ so the value can sit in a URL or a JWT segment without being escaped.
Tools mentioned in this post
- Base64 Encoder & Decoder Encode text to Base64 and decode Base64 back to text, with URL-safe and UTF-8 support. Runs locally inside your…
- JWT Decoder Decode a JWT and inspect its header, payload, and expiry. Tokens are decoded in your browser and never uploaded to a…
- Hash Generator Generate MD5, SHA-1, SHA-256, and SHA-512 hashes from text or files. Computed in your browser — nothing is uploaded.