Workflows
Base64 Encoding and Decoding: What It Is and What It Is Not
Base64 is an encoding, not a lock. Anyone who sees it can read it - here is what it is for and what it is not.
Base64 is everywhere in computing - in email attachments, in authentication headers, in JSON payloads, in CSS data URIs - and it is misunderstood almost everywhere it appears. The misunderstanding is specific: people think it is encryption. It is not. It is a way of writing binary data as text, and anyone who sees it can read it.
What Base64 actually does
Base64 takes bytes and rewrites them using 64 printable characters - the upper- and lower-case letters, the digits, + and /, with = for padding. That is the entire trick.
Why 64? Because 64 is the largest power of two that fits inside the printable ASCII range, and because the systems that carry text - email, HTTP headers, JSON, XML - were designed for text, not for arbitrary bytes. A JPEG in an email attachment, a password in a Basic Auth header, an image embedded in a CSS file: all of them are Base64, and all of them are there because the transport layer only speaks text.
The encoding is lossless: encode and then decode, and you get back the exact bytes you started with, down to the last one. A Base64 string is not smaller than the data it represents - it is about a third larger, because 6 bits of data are spread over 8 bits of character.
Why it is not encryption
This is the important part, and it is where people get hurt.
Base64 is reversible by anyone. There is no key, no password, no secret. The algorithm is public, the alphabet is public, and a Base64 string decodes in any tool in any language in a fraction of a second. It is the same level of security as writing a word backwards.
If you encode a password in Base64, you have not protected it. You have just made it harder to read at a glance. Anyone who intercepts it has it.
The confusion exists because Base64 looks like a secret - it is a long string of gibberish that the application does not display. But the gibberish is a format, not a cipher, and the application is hiding it because it is ugly, not because it is private.
The actual security mistake is usually one of these:
- Storing a database password in Base64 in a config file, and thinking it is "encoded" rather than "plaintext in a different alphabet".
- Putting a token in a URL and assuming the encoding hides it. A token in a URL is in the browser history, the server logs, and the referrer header - Base64 changes none of that.
- Using Base64 to "hide" an API key in client-side JavaScript. The key is in the source; the encoding is cosmetic.
None of those are Base64's fault. It is an encoding, and it does its job. The job is not secrecy.
The encoding detail that breaks scripts
The thing that goes wrong in practice is the character set.
Base64 operates on bytes. If your text has an accent, an emoji or a non-Latin character, you have to decide which bytes to encode - and that means deciding an encoding. UTF-8 is the only sane choice today, but a lot of older scripts and libraries encode the characters as Latin-1, or as the platform's default encoding, and the result decodes as garbage on the other end.
The Base64 tool encodes as UTF-8 before Base64, so the round trip is exact. If you are writing your own, the rule is:
- Text to UTF-8 bytes.
- Bytes to Base64.
- Base64 to bytes.
- Bytes to UTF-8 text.
Skip step 1 and you have a script that works for English and breaks for everything else.
The line-break trap
A lot of tools wrap Base64 output at 76 characters, the old email limit. So the string you copy out of a tool looks like this:
SGVsbG8sIFdvcmxkIQ==
...but in an email it arrives as several lines, and a strict decoder rejects it because the newlines are not part of the alphabet.
The fix is to strip whitespace before you validate. The Base64 tool does that, so a wrapped string decodes fine. If you are writing your own decoder, strip first and validate second - in that order.
The padding trap
A Base64 string ends in = characters, and the number of them is not arbitrary. The padding is what makes the length a multiple of 4, because the algorithm processes the input 3 bytes at a time and a short input leaves a remainder that has to be padded out.
The rules:
- The length of a valid Base64 string is always a multiple of 4.
- 0, 1 or 2 equals signs at the end. Never more.
- The padding is part of the string, not decoration. Removing it breaks the decode.
A common mistake is to trim the equals signs off to make the string "cleaner". That works for some decoders and breaks others, and it is never worth the risk - leave them where they are.
The error that tells you what is wrong
A bad Base64 string fails in one of two ways:
- A character that is not in the alphabet. The fix is to find it and remove it - usually a space, a newline, or a character from a different encoding.
- A length that is not a multiple of 4. The fix is to add the padding back.
A useful decoder names which one happened. "Not valid Base64" is not useful. "The character ! is not allowed" and "the length must be a multiple of 4" are.
A short checklist
- Base64 is an encoding, not a lock. Anyone can decode it.
- Never use it to hide a secret. It is the wrong tool for that, and it is not a tool for that at all.
- Encode as UTF-8 first if the text has accents, emoji or non-Latin characters.
- Strip whitespace before validating, so wrapped strings decode.
- Keep the padding. The equals signs are part of the string.
- The length is always a multiple of 4. That is a quick, reliable check.
- It runs in your browser and keeps no copy of what you paste.
- For anything that has to stay secret, use an actual encryption tool, not an encoding.