What is Base64?
Base64 is a binary-to-text encoding scheme that represents arbitrary binary data using only 64 printable ASCII characters: A–Z (26), a–z (26), 0–9 (10), and two additional characters (+ and / in standard; - and _ in URL-safe).
Key point: Base64 is encoding, not encryption. Anyone can decode Base64 trivially — there is no secret key. Its purpose is safe transmission of binary data (images, files, binary protocols) over channels that only support text: HTTP headers, JSON strings, email (MIME), XML attributes, and HTML data: URIs.
A 3-byte input (24 bits) becomes 4 Base64 characters (6 bits each). This means Base64 increases data size by approximately 33%.
The Three Base64 Variants
| Variant | Char 62 | Char 63 | Padding | RFC | When to use |
|---|---|---|---|---|---|
| Standard | + | / | = | RFC 4648 §4 | Email, file transfer, non-URL contexts |
| URL-safe | - | _ | = | RFC 4648 §5 | URL query params, file names |
| Raw URL-safe | - | _ | None | RFC 4648 §5 | JWT tokens, OAuth tokens |
The + and / in Standard Base64 are URL-unsafe — + means space in form encoding and / is the URL path separator. URL-safe Base64 replaces them to avoid this ambiguity.
JavaScript Base64
// Browser / Node.js — built-in btoa/atob (text only, NOT binary-safe)
const encoded = btoa("Hello, World!"); // "SGVsbG8sIFdvcmxkIQ=="
const decoded = atob("SGVsbG8sIFdvcmxkIQ=="); // "Hello, World!"
// For binary data in Node.js, use Buffer
const buf = Buffer.from("Hello, World!");
const b64 = buf.toString("base64"); // Standard Base64
const urlSafe = buf.toString("base64url"); // URL-safe (Node 16+)
// Decode Base64 back to string
const back = Buffer.from(b64, "base64").toString("utf8");
// URL-safe to standard conversion (manual, if needed)
const toStandard = (s) => s.replace(/-/g, "+").replace(/_/g, "/");
const toUrlSafe = (s) => s.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
// Encode an image file to Base64 data URI
const { readFileSync } = require("fs");
const imgData = readFileSync("logo.png");
const dataUri = `data:image/png;base64,${imgData.toString("base64")}`;Go Base64 Examples
import (
"encoding/base64"
"fmt"
)
data := []byte("Hello, World!")
// Standard Base64 (RFC 4648 §4)
std := base64.StdEncoding.EncodeToString(data)
fmt.Println(std) // => "SGVsbG8sIFdvcmxkIQ=="
// URL-safe Base64 (RFC 4648 §5)
urlSafe := base64.URLEncoding.EncodeToString(data)
fmt.Println(urlSafe) // Same here — "Hello, World!" has no + or /
// Raw URL-safe (no padding — used in JWT)
rawURLSafe := base64.RawURLEncoding.EncodeToString(data)
fmt.Println(rawURLSafe) // => "SGVsbG8sIFdvcmxkIQ" (no ==)
// Decode
decoded, err := base64.StdEncoding.DecodeString(std)
if err != nil {
panic(err)
}
fmt.Println(string(decoded)) // => Hello, World!
// Fix missing padding before decoding (common when receiving raw Base64)
func addPadding(s string) string {
switch len(s) % 4 {
case 2: return s + "=="
case 3: return s + "="
}
return s
}Python Base64 Examples
import base64
data = b"Hello, World!"
# Standard Base64
std = base64.b64encode(data).decode()
print(std) # => "SGVsbG8sIFdvcmxkIQ=="
# URL-safe Base64
url_safe = base64.urlsafe_b64encode(data).decode()
print(url_safe) # => "SGVsbG8sIFdvcmxkIQ==" (same for this input)
# Raw URL-safe (strip padding)
raw = base64.urlsafe_b64encode(data).decode().rstrip("=")
print(raw) # => "SGVsbG8sIFdvcmxkIQ"
# Decode (add padding back if missing)
def decode_base64(s: str) -> bytes:
padding = 4 - len(s) % 4
if padding != 4:
s += "=" * padding
return base64.urlsafe_b64decode(s)
# Encode a file to Base64
with open("image.png", "rb") as f:
img_b64 = base64.b64encode(f.read()).decode()
data_uri = f"data:image/png;base64,{img_b64}"Common Use Cases
JWT tokens use Raw URL-safe Base64 (no padding) for all three parts: header.payload.signature
HTML data URIs use Standard Base64: <img src="data:image/png;base64,iVBORw0...">
Email attachments (MIME) use Standard Base64 with line breaks every 76 characters per RFC 2045
HTTP Basic Authentication encodes username:password as Standard Base64 in the Authorization: Basic header
JSON APIs use Base64 to embed binary fields (e.g., a thumbnail image or cryptographic signature) in a JSON string field
Common Mistakes and Pitfalls
Wrong variant — the most common mistake:
// Standard Base64 in a URL — + and / break URL parsing
const encoded = btoa("some data with +/chars");
const url = `/api/resource/${encoded}`; // WRONG — + and / are URL-special
// URL-safe Base64 for URLs
const safe = Buffer.from("some data").toString("base64url"); // CORRECTMissing padding when decoding:
Raw Base64 strings (from JWT, OAuth tokens) have no = padding. Decoders expecting padding will throw. Add back the = characters:
function decodeRawBase64(raw) {
const padded = raw + "=".repeat((4 - raw.length % 4) % 4);
return Buffer.from(padded, "base64").toString("utf8");
}Using btoa() with binary data in the browser:
btoa() only handles Latin-1 (ISO-8859-1) strings. For UTF-8 text or binary data use Buffer in Node.js or TextEncoder + manual Base64 in the browser.
Size increase — 33% overhead:
A 1 MB binary file encodes to ~1.33 MB of Base64. For large file transfers, use binary protocols instead of Base64-embedding in JSON when possible.
When to Use Each Variant
| Context | Variant | Why |
|---|---|---|
| JWT header/payload/signature | Raw URL-safe | = padding breaks .-separated format |
| OAuth tokens, PKCE verifier | Raw URL-safe | URL-safe, no padding needed |
| Email attachments (MIME) | Standard | RFC 2045 requires standard Base64 |
HTML data: URI | Standard | Standard Base64 only |
| URL query parameters | URL-safe | Avoids + and / conflicts |
| File names | URL-safe | / in filename is a path separator |
| JSON string field (binary data) | Standard | Any variant works; standard is most common |
Use JSONKit's Base64 Encoder/Decoder for instant browser-based encoding and decoding of any text or file — no installation required.