What is Base64? Encoding, not encryption
Base64 hides nothing. It turns any data into letters, digits and a few symbols so it can travel through systems that only handle text, and anyone can undo it in a second. It is worth understanding anyway: it shows up in emails, tokens and URLs, and the bugs it causes are always the same ones.
What Base64 does
RFC 4648 defines Base64 as a way to represent arbitrary sequences of bytes in a form that allows both upper- and lowercase letters but need not be human readable. It uses a 65-character subset of US-ASCII: 64 characters to carry data (A–Z, a–z, 0–9, + and /), enough to represent 6 bits each, plus = for padding.
The process takes the input three bytes at a time (24 bits), splits them into four groups of 6 bits and turns each into one character. That is the whole idea, and it explains the two facts everyone should know: the output is made only of printable characters, and it is about a third larger than the input, because 3 bytes become 4 characters. Ten bytes become 16 characters, 1,000 bytes become 1,336, and 3 MB become 4 MB.
A short example: the text Ana:clave encodes to QW5hOmNsYXZl. Paste that into the Base64 encoder and decoder and you get the original back, which is exactly the point.
It is not encryption
This is the misunderstanding with consequences. Base64 has no key and no secret: decoding is a mechanical step that anybody can do. It is used to make data transportable, not private. If a password, a token or a document is "protected" only by Base64, it is not protected.
The HTTP "Basic" authentication scheme shows how this plays out. It sends the user name and password joined by a colon and encoded with Base64. RFC 7617 states plainly that the scheme is not a secure method of user authentication unless used with something like TLS, because the user ID and password are passed over the network as cleartext. Base64 there is just a convenient wrapper, and the security comes (or does not come) from HTTPS. The same applies to the payload of a JWT, which is base64url-encoded and readable by anyone holding the token (see how to read a JWT).
Where you will see it
- Email attachments. Email was built for text; files are Base64-encoded (MIME) to travel inside a message. This is one reason an attachment adds roughly a third to the size on the wire.
- Data URIs. Small images embedded directly in HTML or CSS look like
data:image/png;base64,iVBOR…. Convenient for tiny icons, wasteful for big images because of the extra third and because they cannot be cached separately. - JSON and APIs. JSON has no binary type, so files and keys are often sent as Base64 strings.
- Tokens and keys. JWTs, certificates in PEM format and many API keys use Base64 or its URL-safe variant.
The padding: why there is sometimes an =
Input comes in groups of three bytes. When the last group has only one or two bytes, the output is padded with = signs so its length is a multiple of 4: one leftover byte gives two =, two leftover bytes give one. The padding carries no information; it just tells the decoder how many bytes the last group held. RFC 4648 notes that when the length of the data is known in advance, padding can be omitted, which is what base64url usually does.
Base64url: the URL-safe variant
The characters + and / have special meaning in URLs and file names. RFC 4648 section 5 defines a variant that replaces them with - and _, and says it should be referred to as "base64url" rather than just "base64". JWTs use it. Mixing them up is a common source of decode errors: a base64url string fed to a plain decoder fails as soon as it hits a - or _. For example, the three bytes 251, 255, 254 encode as +//+ in Base64 and as -__- in base64url.
The accents problem (btoa and atob)
Base64 encodes bytes, not text, so how text becomes bytes matters. In browsers, btoa() treats each character as one byte, which only works for code points below 256. MDN documents that passing a character that does not fit in a byte throws an InvalidCharacterError (try btoa("€")). And even when it does not throw, you may get a different result from other tools: btoa("Mañana") gives TWHxYW5h, because the "ñ" is treated as the single byte 0xF1, while a UTF-8 encoder gives TWHDsWFuYQ==, with "ñ" as two bytes. When you exchange Base64 text with other systems, the right choice is almost always to convert the text to UTF-8 bytes first, then encode. The tool above does that.
Common decoding errors
- Invalid character or length: spaces, line breaks or a missing character from copy and paste. Some decoders tolerate whitespace, others do not.
- Wrong alphabet: a URL-safe string (
-,_) sent to a standard decoder, or the reverse. - Missing padding: some decoders insist on the
=signs; add them until the length is a multiple of 4. - Garbled text after decoding: the bytes were decoded correctly but read with the wrong character set. If the original was UTF-8, read it as UTF-8.
Sources and further reading
- RFC 4648: The Base16, Base32, and Base64 Data Encodings
- RFC 7617: The 'Basic' HTTP Authentication Scheme
- MDN: Window.btoa() (Unicode strings)
Figures checked on 3 October 2026.
Do it now, free, in your browser. Your files are not uploaded.
Convert text, files and images to and from Base64, in your browser.
Frequently asked questions
Is Base64 encryption?
Why is Base64 output bigger than the input?
What does the = at the end mean?
What is the difference between Base64 and Base64url?
Why does btoa() fail with accented characters or the euro sign?
Is it safe to put a password in Base64 in an HTTP header?
Related guides
Tools used in this guide
They run in your browser, so nothing is uploaded.