What is Base64 Encoding? A Complete Guide with Examples
If you have worked with APIs, email attachments, data URLs, or authentication tokens, you have used Base64 whether you realised it or not. It is one of the most widely used encoding schemes in computing, yet it is also one of the most misunderstood. Developers regularly confuse it with encryption, misapply it to problems it does not solve, or use it where it is not needed. This guide explains exactly what Base64 is, how it works mathematically, where it is legitimately useful, and where you should not use it.
What is Base64?
Base64 is an encoding scheme that converts binary data into a string of printable ASCII characters. It uses an alphabet of 64 characters: uppercase letters A–Z (26), lowercase letters a–z (26), digits 0–9 (10), and the symbols + and / (2). A 65th character, =, is used for padding.
The name comes directly from this alphabet size: base 64. Just as decimal numbers use base 10 (10 digits) and hexadecimal uses base 16 (16 characters), Base64 uses 64 characters as its "digits."
The key property of Base64 is that every character in its output is a safe, printable ASCII character. This makes Base64-encoded data safe to put anywhere that text is expected: email bodies, JSON strings, URLs, HTML attributes, XML documents, and HTTP headers.
How Base64 Encoding Works
Base64 converts every 3 bytes of binary data into 4 ASCII characters. Here is the step-by-step process:
Take 3 bytes of input data (24 bits total). Split those 24 bits into four groups of 6 bits each. Use each 6-bit group as an index into the 64-character alphabet. The result is 4 ASCII characters that represent those 3 original bytes.
Since 2⁶ = 64, a 6-bit group can represent any index from 0 to 63 — exactly the size of the Base64 alphabet. This is why exactly 64 characters were chosen: they map perfectly to 6-bit groups.
If the input is not divisible by 3, padding is added. 1 remaining byte becomes 2 output characters plus ==. 2 remaining bytes become 3 output characters plus =. The = padding characters tell the decoder how many bytes were in the final group.
A concrete example
Input string: "Man" ASCII bytes: 77 97 110 Binary: 01001101 01100001 01101110 6-bit groups: 010011 010110 000101 101110 Base64 index: 19 22 5 46 Base64 chars: T W F u Output: "TWFu"
This 3:4 ratio means Base64 output is always 33% larger than the input. Three bytes in, four characters out. This overhead is the trade-off for making binary data safe to transmit as text.
Base64 vs Encryption: A Critical Distinction
Base64 is not encryption. It provides zero security. Anyone who sees a Base64-encoded string can decode it instantly — the algorithm is public, reversible, and requires no key. Encoding password123 as cGFzc3dvcmQxMjM= hides nothing; it is trivially decoded by anyone.
Do not store passwords or secrets in Base64. Base64 is encoding, not encryption. Use bcrypt or Argon2 for passwords, and AES-256 or ChaCha20 for data that needs genuine confidentiality.
The confusion arises because Base64 strings look scrambled. They are not — they are simply reformatted. Think of it like Pig Latin: the words look different but there is no secret, and anyone who knows the rules can decode them immediately.
Where Base64 is Genuinely Useful
Embedding images in HTML and CSS (Data URLs)
You can embed images directly into HTML or CSS without a separate file request using a data URL. The image binary is Base64-encoded and embedded inline. This eliminates one HTTP request per image, which matters most for small icons and UI elements.
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==" alt="1x1 pixel">
/* Same technique in CSS */
.icon {
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==");
}
Transmitting binary data through text-only channels
Email was originally designed for 7-bit ASCII text. MIME attachments use Base64 to encode binary files (PDFs, images, executables) into text that email servers can safely relay. This is why email attachments are Base64-encoded under the hood.
Similarly, when you send binary data in a JSON API request (a file upload, an image, a certificate), you often Base64-encode it so it fits safely in a JSON string field. JSON strings are Unicode text — they cannot directly contain arbitrary binary bytes.
HTTP Basic Authentication
HTTP Basic Auth sends credentials as username:password encoded in Base64 in the Authorization header. This is purely for safe transport in an HTTP header — it is not encryption. HTTPS is what provides the security; the Base64 is just formatting.
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ= # Decodes to: username:password
JWT Tokens
JSON Web Tokens (JWTs) use Base64URL encoding (a variant using - and _ instead of + and / so the token is URL-safe). A JWT has three Base64URL-encoded sections separated by dots: header, payload, and signature. The header and payload are just Base64-encoded JSON — anyone can decode them. The signature is what provides security — it verifies the token was not tampered with.
Encoding binary data in XML and JSON APIs
Neither XML nor JSON has a native binary data type. When an API needs to return binary data — a thumbnail, a PDF, a cryptographic key — it Base64-encodes the binary into a string field. The receiver decodes it back to binary. This is standard practice in REST APIs, GraphQL, and SOAP web services.
Base64 Variants You Will Encounter
| Variant | Chars 62–63 | Padding | Used in |
|---|---|---|---|
| Standard Base64 | + / | = required | Email (MIME), general purpose |
| Base64URL | - _ | = optional | JWTs, URLs, filenames |
| Base64 MIME | + / | = required | Email MIME, line breaks at 76 chars |
The URL-safe variant (Base64URL) replaces + with - and / with _ because + and / have special meanings in URLs (space and path separator respectively). Always use Base64URL when the encoded string will appear in a URL or filename.
Encoding and Decoding Base64 in Code
JavaScript (Browser)
// Encode a string to Base64
const encoded = btoa("Hello, World!");
console.log(encoded); // "SGVsbG8sIFdvcmxkIQ=="
// Decode Base64 to a string
const decoded = atob("SGVsbG8sIFdvcmxkIQ==");
console.log(decoded); // "Hello, World!"
// For binary data (files, images), use FileReader or Buffer in Node.js
// btoa/atob only work reliably with ASCII strings
// Node.js (Buffer approach — handles all binary data)
const encoded = Buffer.from("Hello, World!").toString("base64");
const decoded = Buffer.from(encoded, "base64").toString("utf8");
Python
import base64 # Encode bytes to Base64 string data = b"Hello, World!" encoded = base64.b64encode(data) print(encoded) # b'SGVsbG8sIFdvcmxkIQ==' # Decode Base64 string to bytes decoded = base64.b64decode(b"SGVsbG8sIFdvcmxkIQ==") print(decoded) # b'Hello, World!' # URL-safe variant (for JWTs, URLs) encoded_url = base64.urlsafe_b64encode(data) decoded_url = base64.urlsafe_b64decode(encoded_url)
Common Mistakes with Base64
Using it for security: Already covered — Base64 is not encryption. Do not use it to "protect" sensitive data.
Overusing it for large files: Base64 increases size by 33%. Embedding a 1MB image as a Base64 data URL in your HTML adds 1.33MB to every page load. Use it for small assets (icons under 10KB); serve large files as separate HTTP resources with proper caching headers.
Mixing standard and URL-safe variants: Standard Base64 with + and / will break in URLs. Always use Base64URL when the output goes into a URL. A common symptom: a Base64 value that works in a tool but produces an error when passed as a query parameter — almost always a + being interpreted as a space.
Forgetting padding: Some systems strip = padding characters. A valid Base64 string must have a length divisible by 4 (padded with = as needed). If your decoder fails with an invalid length error, try adding = padding: s += '=' * (4 - len(s) % 4).
Try encoding and decoding in your browser right now with ToolPry's Base64 Encoder — it handles both standard and URL-safe variants, works with files, and processes everything client-side.