Base64 Explained Like You're Five
Okay, so you've seen it. That long string of letters and numbers that ends with one or two equals signs. Maybe it was in a JWT token, maybe it was inside an HTML email, maybe someone on Stack Overflow told you to "just Base64 encode it." You nodded. You copy-pasted. And now, weeks later, you still don't know what that thing actually is.
Let's fix that. No jargon. No "binary representation of octets." Just a plain talk about what Base64 does, why it exists, and why — this is the important part — it is absolutely not encryption.
Start here: computers only understand numbers
Everything a computer stores or sends is ultimately a number. The letter "A" is stored as the number 65. A smiley face emoji is stored as a much bigger number. A cat photo is stored as millions of numbers all squished together.
When you send data from one place to another — over email, through an API, in an HTML page — you're moving those numbers through a pipe. The problem is that some pipes are old and picky. They were built for plain English text. They choke on certain byte values. They mangle anything that looks weird.
Email is the classic example. The original email protocol (SMTP, designed in the early 1980s) was built to carry 7-bit ASCII text. That's the normal alphabet, digits, and a handful of punctuation marks. Nothing more. Try to shove a PNG image through it in raw form, and the bytes that make up that image would get mangled, misread, or just silently dropped.
So engineers needed a way to take any binary data — images, PDFs, audio files, you name it — and represent it using only safe, boring text characters. Characters that every old system can handle without freaking out.
That's what Base64 is. It's a way of writing binary data using only 64 specific characters.
The 64 characters (and why 64)
Those 64 characters are: A–Z (26 letters), a–z (26 more letters), 0–9 (10 digits), plus "+" and "/". That's 64. Every single byte of your input gets expressed purely using combinations of these characters.
Why 64 specifically? Because 64 is a power of two — it's 2 to the 6th power. Each of these 64 characters can be represented using exactly 6 binary bits. The encoding works by grabbing 3 bytes of input at a time (3 × 8 bits = 24 bits total), then splitting those 24 bits into four 6-bit chunks, and mapping each chunk to one of the 64 characters. Three bytes in, four characters out. Every time.
That's why Base64-encoded data is always roughly 33% larger than the original. You're trading space for compatibility.
And the equals sign you keep seeing at the end? That's padding. When the input data doesn't divide perfectly into groups of three bytes, the encoder adds "=" signs to fill out the last group. It's just a bookkeeping thing.
A tiny example so it sticks
Take the word Man. In ASCII, those three letters have byte values 77, 97, 110. In binary:
M = 01001101
a = 01100001
n = 01101110
Smush them together into one 24-bit stream:
010011010110000101101110
Split into four 6-bit groups:
010011 | 010110 | 000101 | 101110
Those four numbers are 19, 22, 5, and 46. Look those up in the Base64 alphabet table and you get: T, W, F, u.
So "Man" encoded in Base64 is TWFu. You can verify this yourself in your browser console right now:
btoa("Man") // returns "TWFu"
And to decode it:
atob("TWFu") // returns "Man"
No magic. No secrets. Just math.
Now let's kill the biggest myth: Base64 is NOT encryption
This is so important I'm going to say it a few different ways.
Base64 is not encryption. It is not secure. It is not a way to hide data. It is not even close to a password hashing function. Anyone — and I mean literally anyone with a web browser — can decode a Base64 string in two seconds.
Go to any online Base64 decoder, paste in a string, click a button. Done. The data is right there.
Think of it this way: encryption is like locking something in a safe. Only people with the key can open it. Base64 is like writing in pig latin. Sure, it looks weird to a passing glance, but there's no key required. Anyone who knows the system (and the system is completely public) can read it instantly.
Why does this matter? Because developers sometimes make the mistake of putting sensitive things — API keys, passwords, personal data — in Base64 and thinking they've protected something. They haven't. If a Base64-encoded password leaks, it's the same as the password leaking in plain text. Possibly worse, because a false sense of security is more dangerous than no security at all.
Real encryption (AES, RSA, ChaCha20) uses a secret key. Without the key, the data is computationally impossible to recover in any reasonable amount of time. Base64 uses no key. The "encoding scheme" is printed on Wikipedia. It is public by design.
So where does Base64 actually show up?
Once you start noticing it, you see it everywhere in real dev work.
Email attachments. When you send a PDF over email, your email client encodes it as Base64, embeds it in the message body as text, and the recipient's client decodes it back. This is part of the MIME standard and it's been working this way for about 35 years.
Data URIs in HTML/CSS. You've probably seen something like src="data:image/png;base64,iVBORw0KGgo..." in HTML. That's a full image, encoded as Base64 and dropped right into the markup. No separate file. Useful for small icons and loading spinners, though it inflates page size so don't go overboard.
JWTs (JSON Web Tokens). That long string your authentication system hands back after login? It's three Base64url-encoded chunks joined by dots. The header, the payload (which contains your user ID, role, expiry, etc.), and the signature. The first two parts are just Base64. Anyone can decode them. The third part — the signature — is what actually makes JWTs trustworthy, because it's cryptographically signed with a secret key. The data itself isn't hidden; it's the signature that proves the data hasn't been tampered with.
HTTP Basic Auth. When a browser sends Basic authentication, it takes username:password, Base64-encodes it, and puts it in the Authorization header. This is why Basic Auth should only ever be used over HTTPS. Over plain HTTP, anyone sniffing the network can decode that header and have your password in plaintext in seconds.
Storing binary data in JSON or XML. JSON doesn't have a binary type. If you want to include an image or a certificate inside a JSON payload, you Base64-encode it and put it in a string field. Same with XML. It's clunky, but it's standard.
Environment variables and config files. You'll sometimes see Base64 used to avoid special-character headaches in config files. A private key that contains newlines and slashes doesn't paste well into a .env file, but Base64-encoded, it's a clean single-line string. Again — this is convenience, not security.
The URL-safe variant (Base64url)
Quick heads-up: standard Base64 uses "+" and "/" as its two extra characters. Those characters have special meaning in URLs — "+" means a space in query strings, "/" separates URL path segments. So when Base64 is used inside URLs or tokens (like JWTs), a slightly different alphabet is used: "-" instead of "+" and "_" instead of "/". This variant is called Base64url. Same idea, just URL-friendly characters.
You'll see both variants in the wild. They're interchangeable in concept, just use the right one for the right context.
Decoding it yourself (the quick way)
Browser console (works in Chrome, Firefox, Safari, Edge):
// Encode
btoa("hello world") // "aGVsbG8gd29ybGQ="
// Decode
atob("aGVsbG8gd29ybGQ=") // "hello world"
Command line:
# Encode
echo -n "hello world" | base64
# Decode
echo "aGVsbG8gd29ybGQ=" | base64 --decode
Python:
import base64
base64.b64encode(b"hello world") # b'aGVsbG8gd29ybGQ='
base64.b64decode("aGVsbG8gd29ybGQ=") # b'hello world'
The one-line summary
Base64 takes binary data and converts it into a string of 64 safe, boring text characters so it can travel through systems that only understand text. It makes data portable, not private. Any time you see it, remember: that data is readable by absolutely anyone. If there's something sensitive in there, something else (TLS, actual encryption, a signature) needs to be doing the protecting — not the Base64 itself.
That's it. That's Base64. You've got this.