Skip to content
Developer toolsEncodingSecurity

Base64 is not encryption

Base64 is a transport encoding with no key and no secrecy. What the padding means, why base64url exists, the Unicode trap in btoa, and when to reach for a hash instead.

Ashish S Kumar5 min read

Base64 shows up in the same places every time — a data URI in a stylesheet, the middle section of a JWT, an Authorization header, an image pasted into a JSON payload. Because the output looks like line noise, it gets treated as though it hides something. It does not, and a surprising number of security incidents start with someone assuming otherwise.

What it actually does

Base64 is a transport encoding. It takes arbitrary bytes and re-expresses them using 64 characters that survive systems which only handle text — A–Z, a–z, 0–9, and two more. Three bytes of input become four characters of output, which is where the roughly 33% size increase comes from. When the input does not divide evenly into three, the output is padded with one or two `=` characters.

The point of the encoding is that the result passes through things that mangle raw bytes: email bodies, URL query strings, XML attributes, terminals. Pick the wrong variant and it still breaks, which is the next section. RFC 4648 defines both the alphabet and the padding rules, and it is short enough to read in one sitting.

Encode or decode, with Unicode handled

Runs in your browser — nothing is uploaded. Open the full base64 encoder

Standard base64 and base64url are not interchangeable

Standard base64 uses `+` and `/` for its last two characters. Both are meaningful in a URL: `+` decodes to a space in form-encoded data, and `/` is a path separator. Put a standard base64 string in a query parameter and something downstream will eventually corrupt it.

base64url swaps those two for `-` and `_`, and usually drops the `=` padding because it also has meaning in a query string. Same bytes, different alphabet.

Standard base64base64url
Characters 62 and 63+ and /- and _
Padding= to a multiple of fourUsually omitted
Safe in a URL or filenameNoYes
Where you see itData URIs, MIME, Basic authJWTs, JWKs, URL tokens

If a decode fails with "invalid character" on a token that looks fine, this is almost always why — the string is base64url and the decoder wants padded standard base64. Percent-encoding is a different mechanism for a related problem; the URL encoder handles that one.

Percent-encode a value for a query stringPercent-encode a value, a whole URL, or a form field.

The Unicode trap in the browser

JavaScript ships `btoa()` and `atob()`, and they look like the obvious answer. They are not, because `btoa()` operates on a string of single-byte characters. Hand it anything above U+00FF — an emoji, a Devanagari or Cyrillic word, a curly quote pasted from a word processor — and it throws `InvalidCharacterError`.

The fix is to convert the text to bytes first with `TextEncoder`, encode those bytes, and reverse the process with `TextDecoder` on the way back. The old `unescape(encodeURIComponent(...))` workaround still circulates and still mostly works, but it leans on a deprecated function to do a job `TextEncoder` does correctly.

Where people get it wrong

Three mistakes account for most of them, and all three come from treating an encoding as a security control.

  1. 1Base64-ing a password, an API key or a connection string before storing or logging it. This obscures nothing. Anyone who can read the log can read the secret, and now it is not even greppable as a known-bad string.
  2. 2Assuming the payload of a JWT is private. The middle segment is base64url and readable by anyone holding the token — including the person it was issued to. Never put anything in a JWT you would not hand to its bearer.
  3. 3Treating HTTP Basic authentication as protected. `Authorization: Basic` is the username and password joined by a colon and base64-encoded. Over plain HTTP that is a credential in the clear with extra steps.

If the goal is that nobody can read it, you want encryption and a key. If the goal is to verify something has not changed, you want a hash — one-way by design, so there is nothing to reverse. The hash generator covers the second case; the first belongs in a library and a key store, not a web page.

SHA-256 and friends, for the one-way caseSHA-1 through SHA-512, all at once, as you type.

When base64 is the right answer

It has real uses, and they all share a shape: bytes need to travel through a channel that only carries text.

  • Inlining a small image or font as a data URI, where an extra request costs more than the 33% size penalty.
  • Putting binary content inside JSON, which has no byte type of its own.
  • Email attachments, which is the original reason the encoding exists.
  • Anything that must survive a copy-paste through a chat window, a spreadsheet cell or a terminal.

The size penalty is the thing to weigh. A 40KB image becomes about 54KB inline, and it cannot be cached separately from the document that carries it. For one small icon that is a good trade. For a hero image it is not.

Frequently asked questions

Is base64 encryption?
No. Encryption needs a key, and without it the original is unrecoverable. Base64 needs nothing — the transformation is public and reversible by anyone. It provides no confidentiality whatsoever.
Why does my base64 string end in one or two equals signs?
That is padding. Base64 works on three-byte groups producing four characters. When the input length is not a multiple of three, the last group is padded so the output still divides by four. One leftover byte gives two equals signs, two leftover bytes give one.
Can I put a base64 string in a URL?
Not standard base64 — its `+` and `/` characters will be misread, and `=` has meaning in a query string. Use the base64url variant, which substitutes `-` and `_` and normally drops the padding.
Why does btoa() throw on my text?
`btoa()` only accepts characters in the range U+0000 to U+00FF. Emoji, accented characters in some forms, and any non-Latin script fall outside it. Convert the string to bytes with `TextEncoder` first, then encode those bytes.
Does base64 make a file smaller?
The opposite — it makes it about a third larger, because every three bytes become four characters. It is used to make bytes transportable as text, never to compress them.
Is it safe to decode a token in an online tool?
It depends entirely on whether the page sends your input anywhere. This one does the work in your browser and transmits nothing, but the safe habit with a production credential is to assume any page might, and use a local command instead.

Sources

  1. 1.RFC 4648 — The Base16, Base32, and Base64 Data EncodingsIETF
  2. 2.URL StandardWHATWG