On this page
- What Base64 is, and what it is not
- Why 64 characters, and why bytes of three
- UTF-8, and why plain btoa breaks on accents
- Where Base64 actually shows up
- Standard, URL-safe, and MIME variants
- A worked example with padding
- Security myths worth putting down
- The size cost, and when not to use it
- Common mistakes
- Sources
What Base64 is, and what it is not
Base64 is a way of writing bytes using only characters that are safe to send through text-based systems. It takes any group of bytes, whether they came from a photo, a PDF, a cryptographic signature, or a plain English sentence, and rewrites them using an alphabet of sixty-four characters. The result is a string that looks like random letters and numbers, ends in an equals sign every now and then, and can be pasted into a JSON field, an email header, or a URL fragment without escaping.
What Base64 is not is encryption. There is no key, no password, no secret involved. Anybody who has the string can decode it back to the original bytes in a fraction of a second, and this tool does exactly that in the Decode direction. If your goal is to keep something secret, Base64 does nothing for you. If your goal is to move bytes through a channel that only understands text, Base64 is the standard answer, and it has been for decades.
The other thing Base64 is not is compression. The encoded output is always larger than the input, by roughly a third before any wrapping. A photograph that is 300 kilobytes on disk becomes about 400 kilobytes of Base64 text. That cost is worth paying when the alternative is a broken attachment or a rejected request, and it is not worth paying when the bytes could simply be sent as bytes.
Why 64 characters, and why bytes of three
The name comes from the size of the alphabet. Sixty-four characters, each representing six bits of data, are enough to cover every possible combination of six binary digits. Four such characters carry twenty-four bits, which is exactly three bytes. That is why Base64 groups the input into chunks of three bytes and produces four characters of output for each chunk. The arithmetic is clean and it has not changed since the earliest specifications.
The standard alphabet, defined in RFC 4648, is upper-case A to Z, lower-case a to z, the digits 0 to 9, then plus, then slash. That is sixty-two characters, plus two more for the full set of sixty-four. The equals sign is not part of the alphabet. It is a padding character, used when the input length is not a multiple of three. One or two equals signs at the end tell a decoder how many bytes of the original data were in the final partial group.
An important consequence of the three-byte grouping is that the length of a Base64 string is always a multiple of four. A string whose length is not a multiple of four is either missing padding, wrapped across lines, or corrupted. Many decoders will complain the moment they see it. Others will try to guess the missing padding and may get it wrong. When you are producing Base64 for a strict system, leave the padding in place and keep the string on one line.
UTF-8, and why plain btoa breaks on accents
The browser has a built-in function called btoa that turns a string into Base64, and a matching atob that turns Base64 back into a string. The catch, which has tripped up generations of developers, is that btoa treats each character as one byte. For plain ASCII text, English letters, digits, and basic punctuation, that is fine. The moment the input contains a character that occupies more than one byte in UTF-8, such as an accented letter, an emoji, a Chinese character, or a Swahili word with diacritics, btoa throws an error. It cannot represent a code unit above 255.
The fix is to convert the string to bytes first, then encode the bytes. This tool uses the browser's own TextEncoder, which produces a Uint8Array of UTF-8 bytes, and passes that array through a small loop that builds the binary string btoa expects. On the decode side, it strips whitespace, runs the reverse, and uses TextDecoder with the UTF-8 label and the fatal flag set, so that genuinely invalid byte sequences raise a clear error instead of quietly producing replacement characters.
This matters more than it used to. Text that passes through APIs, tokens, or configuration files often contains characters well outside ASCII, and a Base64 tool that only works for English is a trap. The same reasoning applies to the decode direction. A Base64 string that came from a UTF-8 source should decode cleanly into readable text. A string that came from a JPEG or a zip file will not, because the bytes do not represent text at all.
The rule of thumb. If you are encoding or decoding text that a human will read, use a tool that goes through UTF-8 bytes. If you are moving binary files, use a tool that writes the decoded bytes straight to a file, not one that prints them into a text area.
Where Base64 actually shows up
Base64 appears in more places than most people expect, and once you know the shape, you start seeing it everywhere.
- Data URLs. A small image, icon, or font can be embedded directly in HTML or CSS as a
data:URL, with the payload in Base64. This saves a network request, at the cost of a larger HTML file. - Email attachments. RFC 2045 defines Base64 as the standard way to carry binary attachments through SMTP, which was designed for seven-bit text.
- JSON payloads. Some APIs accept or return binary blobs as Base64 strings when the surrounding format is JSON and there is no cleaner way to represent bytes.
- JSON Web Tokens. A JWT is three Base64URL-encoded segments separated by dots, carrying a header, a payload, and a signature. The payload is readable by anyone who has the token.
- Basic authentication headers. The
Authorization: Basicheader is the username and password joined by a colon and encoded in Base64. It is not encrypted, only encoded, which is why Basic auth is only acceptable over HTTPS. - Configuration files and environment variables. A certificate, a private key, or a small binary secret is often stored as a Base64 string because the surrounding file format does not handle raw bytes well.
- Database dumps and log files. When a binary column needs to survive a text-only export, Base64 is the usual transport.
Once you spot the pattern, you can also spot the mistake. A password stored as Base64 in a configuration file is a password that anybody with file access can read. A session cookie that is Base64 and not signed is a session cookie that anybody can forge. The encoding has a purpose, but it is not to hide anything.
Standard, URL-safe, and MIME variants
Base64 comes in three flavours that look similar but are not always interchangeable. Using the wrong variant is one of the most common reasons a string that looks valid gets rejected.
| Variant | Alphabet | Padding | Where it is used |
|---|---|---|---|
| Standard | A–Z, a–z, 0–9, +, / | Yes (=) | General-purpose encoding, data URLs, most APIs |
| URL-safe (Base64URL) | A–Z, a–z, 0–9, -, _ | Usually omitted | JSON Web Tokens, OAuth, some cloud APIs |
| MIME | Same as standard | Yes | Email attachments, wrapped at 76 characters |
The URL-safe variant exists because plus and slash have special meanings inside a URL. A plus can be interpreted as a space by some servers, and a slash is a path separator. Replacing them with hyphen and underscore produces a string that can travel inside a query parameter or a path segment without escaping. The padding is often dropped for the same reason, and the length is rounded up rather than filled.
Because the alphabets overlap for most characters, a standard Base64 string and a Base64URL string look identical up to the first plus or slash. That is what makes the mismatch so easy to miss. A JWT signature that contains a plus sign has almost certainly been re-encoded from a Base64URL source, and the receiving service will reject it even though the characters decode cleanly.
A worked example with padding
Take the word "cat". In UTF-8 that is three bytes: 0x63, 0x61, 0x74. Grouped together, twenty-four bits, split into four six-bit chunks: 011000 110110 000101 110100. Mapped through the standard alphabet, those are Y, 2, F, 0. The Base64 for "cat" is Y2F0, with no padding needed because the input length was exactly three bytes.
Now take the word "ca". Two bytes: 0x63, 0x61. Sixteen bits, padded with zeros to reach twenty-four: 011000 110110 000100 000000. Mapped: Y, 2, E, and the last chunk is zero, which is not a character but a padding position. The result is Y2E=, with one equals sign to mark that the last group contributed only two bytes of original data.
And the word "c". One byte: 0x63. Padded to twenty-four bits: 011000 110000 000000 000000. Mapped: Y, w, then two padding positions. The result is Yw==, with two equals signs to mark that only one byte was in the final group.
Working through these three cases makes the padding rule concrete. Every Base64 encoder in every language produces the same output for the same input, because the spec leaves no room for variation. If two tools disagree on the same short string, one of them is using the wrong alphabet or is silently dropping padding.
Security myths worth putting down
A surprising number of security problems trace back to somebody treating Base64 as if it were protection. Three myths come up again and again.
"It is encrypted because it looks like gibberish." It is not encrypted. Decoding requires no key, and anybody with a browser can do it. A Base64-encoded password in a configuration file is a plaintext password with extra steps. A Base64-encoded JWT payload is plaintext that anyone can read. The encoding hides the meaning from a casual glance and nothing more.
"It is safe because it is unreadable to my users." Your users are not the threat model. Attackers, auditors, and automated scanners all know what Base64 looks like, and they decode it as a matter of routine. If a string is meant to be confidential, it needs to be encrypted, and the key needs to be managed properly. That is a different problem from encoding, and it needs different tools.
"I can hide logic by encoding it." Anybody with the decoder can read the logic. This is why obfuscation that leans on Base64 is not obfuscation at all. If you need to hide business logic from a determined user, that is a licensing and hosting problem, not an encoding problem.
If you take one thing from this article, take the distinction between encoding and encryption. Encoding changes the representation of data so it can travel. Encryption changes the data so it cannot be read without a key. Base64 is the first. It is not, and never has been, the second.
The size cost, and when not to use it
Every three bytes of input become four characters of output, so Base64 adds about thirty-three per cent to the payload before any additional formatting. Add line breaks every seventy-six characters for MIME, and the overhead edges higher. For a short string, that cost is invisible. For a large file, it is real, and it is worth thinking about before you decide to embed an image as a data URL or ship a binary blob through a JSON API.
The rule that works in practice: Base64 for anything smaller than a few kilobytes that would otherwise need a separate request or a separate file. Plain binary transfer for anything larger, unless the surrounding protocol leaves no choice. A small SVG icon inlined as a data URL saves a network round trip and usually pays for itself. A megabyte of audio embedded the same way bloats the surrounding document and delays the first render.
There is also a readability cost. A JSON field that contains a Base64 blob is unreadable to a human reviewer, which matters during code review, debugging, and postmortems. Where a system can accept a reference, a URL, or a file path instead of an inline blob, use the reference. It is easier to store, easier to cache, and easier to inspect.
Common mistakes
A handful of avoidable errors show up again and again when Base64 is used in real projects.
Mixing variants. A Base64URL string passed into a decoder that expects standard Base64 will fail on the first hyphen or underscore. A standard Base64 string pasted into a JWT library that expects Base64URL will fail on the first plus or slash. Always check which variant the receiving system expects.
Dropping the padding. Some systems tolerate missing padding, some do not. If you are producing output for a strict API, leave the equals signs in place and let the API strip them if it wants to.
Wrapping in the wrong place. MIME wraps at seventy-six characters. Some APIs accept line breaks and some reject them outright. When in doubt, produce a single-line string and let the transport layer handle wrapping.
Encoding a password and calling it stored. A Base64-encoded password is still a password. If you need to store credentials, use a password-hashing function such as bcrypt, scrypt, or Argon2, never an encoding.
Decoding a binary blob into a text area. If the input came from an image, a zip file, or a PDF, decoding it into a text area produces replacement characters and no useful output. The right tool for that job writes the bytes to a file.
Assuming a successful decode proves correctness. A string can be valid Base64 and still contain the wrong bytes. Decoding proves only that the characters were well-formed, not that the content is what you expected. Always compare the decoded output against the original when the round trip matters.
Leaving sensitive text in the input box. This tool does not send or store anything, but a shared computer or a browser extension can still see what is on the page. Clear the fields when you are done.
Sources
The Base64 format is fully specified and the primary sources are short, precise, and worth reading in full if you work with encodings regularly.
Sources
- Internet Engineering Task Force. RFC 4648 — The Base16, Base32, and Base64 Data Encodings. datatracker.ietf.org/doc/html/rfc4648
- Internet Engineering Task Force. RFC 2045 — MIME Part One: Format of Internet Message Bodies. datatracker.ietf.org/doc/html/rfc2045
- Internet Engineering Task Force. RFC 7515 — JSON Web Signature (JWS), defining Base64URL. datatracker.ietf.org/doc/html/rfc7515
- WHATWG. Encoding Standard. encoding.spec.whatwg.org
- W3C. HTML Living Standard — data: URLs. html.spec.whatwg.org
- MDN Web Docs. Base64 — Glossary. developer.mozilla.org/en-US/docs/Glossary/Base64