Base64 Is Not Encryption (and Other Things Worth Knowing About It)
Every so often a security report goes around that boils down to: "The password was stored in Base64." Base64 output looks scrambled, so it's easy to assume it's protecting something. It isn't. It's a way of writing bytes using a limited alphabet, and anyone can reverse it in a fraction of a second.
What Base64 actually does
Computers store everything as bytes, values from 0 to 255. Many of those values are not printable characters, and some (like the null byte or a newline) have special meaning in text protocols. Base64 takes three bytes (24 bits) at a time, splits them into four 6-bit chunks, and maps each chunk to one of 64 characters: A–Z, a–z, 0–9, + and /.
Because four characters represent three bytes, Base64 output is about 33% larger than the input. If the input length isn't a multiple of three, = signs pad the end. That's all there is to it. There's no key, no secret and nothing to crack.
"Hi!" -> bytes 72 105 33 -> "SGkh"
Where it's genuinely useful
Base64 exists to move binary data through systems that were designed for text.
- Email attachments. SMTP was built for 7-bit text, so attachments are Base64-encoded inside MIME messages.
- Data URLs. A small icon can be embedded straight into CSS or HTML as
data:image/png;base64,..., saving an HTTP request. - JSON payloads. JSON has no binary type, so APIs send file contents or cryptographic signatures as Base64 strings.
- Tokens. JWTs use the URL-safe variant so they can travel in headers and URLs without escaping.
Where it gets misused
Kubernetes secrets
A Kubernetes Secret manifest stores values in Base64, which leads a lot of people to believe they're encrypted. They aren't. Anyone who can read the manifest, or has get secrets permission on the cluster, can decode them instantly. Base64 is there because secrets can contain binary data, not for confidentiality. Real protection comes from enabling encryption at rest, restricting RBAC, and keeping secret manifests out of git (tools like Sealed Secrets or an external secrets manager help).
HTTP Basic authentication
The header Authorization: Basic dXNlcjpwYXNzd29yZA== is just user:password in Base64. Without HTTPS, anyone on the network can read it. Basic auth is fine for internal tools behind TLS; it's not a security mechanism by itself.
"Obfuscated" API keys in apps
Encoding an API key in a mobile app or front-end bundle stops nobody. If the key must be secret, it can't live on the client at all. Put it on a server and have the client call that server instead.
Encoding vs hashing vs encryption
| Reversible? | Needs a key? | Purpose | |
|---|---|---|---|
| Encoding (Base64, URL encoding) | Yes, by anyone | No | Represent data in a different format |
| Hashing (SHA-256) | No | No | Fingerprint data, detect changes |
| Encryption (AES, RSA) | Yes, with the key | Yes | Keep data confidential |
If the question is "can someone read this?", only encryption answers it. If the question is "has this changed?", use a hash or, better, a signature.
Practical gotchas
Unicode. The browser's btoa() throws an error on any character outside Latin-1, so btoa("café") works but btoa("你好") fails. Convert the string to UTF-8 bytes first with TextEncoder. Our Base64 tool does this automatically.
Standard vs URL-safe. URL-safe Base64 swaps + and / for - and _ and often drops padding. Decoders that only accept one alphabet will fail on the other, so if you're decoding a JWT segment with a standard decoder, convert those two characters first.
Line breaks. Some encoders, like older versions of openssl base64, insert a newline every 64 or 76 characters. Strict decoders reject them. Strip whitespace before decoding.
The takeaway
Base64 is a transport format, like putting a letter in an envelope so it fits through the mail slot. It's useful, boring and completely transparent. When you see a secret stored in Base64, read it as "stored in plain text, with extra steps."
UTF-8 safe Base64 encoding and decoding, URL-safe mode and file to data URL.
Open the Base64 Encoder / Decoder