base64encodingbinary

Base64 Encoding: The Complete Developer Guide

· Cosyslabs

Base64 encoding converts binary data into ASCII text using a 64-character alphabet, enabling safe transmission over protocols designed for text. Every three bytes of input become four Base64 characters, increasing size by approximately 33%. The encoding is completely reversible and provides no security — it is a data representation format, not encryption.

Why Developers Need Base64

Modern software frequently crosses boundaries between binary and text domains:

  • HTTP headers accept only ISO-8859-1 printable characters
  • JSON is a text format that cannot embed raw binary
  • Email (SMTP) was designed for ASCII text
  • HTML attributes are text strings
  • Environment variables are strings

Base64 bridges these domains by representing any binary data as printable text.

The Encoding Algorithm

Base64 works by regrouping binary data from 8-bit bytes into 6-bit groups:

Step-by-Step

  1. Take input bytes and convert to binary
  2. Concatenate all bits into one stream
  3. Split into groups of 6 bits
  4. Map each 6-bit value (0–63) to a character in the Base64 alphabet
  5. If the input is not divisible by 3, pad with =

The Base64 Alphabet

IndexCharIndexCharIndexCharIndexChar
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/

Plus = for padding.

Worked Example

Input: "API"
Binary: 01000001 01010000 01001001
Groups: 010000 010101 000001 001001
Index:  16     21     1      9
Chars:  Q      V      B      J
Output: "QVBJ"

Padding

When input length is not a multiple of 3:

1 remaining byte → 2 Base64 chars + "=="
2 remaining bytes → 3 Base64 chars + "="
3 remaining bytes → 4 Base64 chars (no padding)

Standard vs URL-Safe Base64

Standard Base64 uses + and / as the 62nd and 63rd characters. These are reserved in URLs, so URL-safe Base64 substitutes them:

PositionStandardURL-Safe
62+-
63/_
Padding=omitted or %3D

JWT tokens use URL-safe Base64 without padding. Web browsers use standard Base64 in btoa()/atob().

// Standard Base64
btoa("Hello+World/Test");
// "SGVsbG8rV29ybGQvVGVzdA=="

// URL-safe (manual conversion)
function toUrlSafe(b64) {
  return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
}

function fromUrlSafe(b64url) {
  const padded = b64url.replace(/-/g, "+").replace(/_/g, "/");
  const pad = (4 - (padded.length % 4)) % 4;
  return padded + "=".repeat(pad);
}

Language Reference

JavaScript / TypeScript

// Browser (strings only — no binary)
const encoded = btoa("Hello, World!");
const decoded = atob("SGVsbG8sIFdvcmxkIQ==");

// Node.js / browser (Uint8Array support)
const encoded = Buffer.from("Hello, World!").toString("base64");
const decoded = Buffer.from("SGVsbG8sIFdvcmxkIQ==", "base64").toString("utf8");

// URL-safe
const urlSafe = Buffer.from("Hello, World!").toString("base64url");

// Binary data (file contents)
import fs from "fs";
const fileBase64 = fs.readFileSync("image.png").toString("base64");

Python

import base64

# Encode string
encoded = base64.b64encode(b"Hello, World!").decode("utf-8")
# "SGVsbG8sIFdvcmxkIQ=="

# Decode
decoded = base64.b64decode("SGVsbG8sIFdvcmxkIQ==").decode("utf-8")

# URL-safe variant
url_safe = base64.urlsafe_b64encode(b"Hello+World").decode()
decoded_us = base64.urlsafe_b64decode(url_safe + "==")  # Add padding if needed

Go

import "encoding/base64"

// Encode
encoded := base64.StdEncoding.EncodeToString([]byte("Hello, World!"))

// Decode
decoded, err := base64.StdEncoding.DecodeString("SGVsbG8sIFdvcmxkIQ==")

// URL-safe
urlEncoded := base64.URLEncoding.EncodeToString([]byte("Hello+/World"))

// URL-safe without padding
rawURL := base64.RawURLEncoding.EncodeToString([]byte("Hello"))

Rust

use base64::{engine::general_purpose, Engine as _};

let encoded = general_purpose::STANDARD.encode(b"Hello, World!");
let decoded = general_purpose::STANDARD.decode("SGVsbG8sIFdvcmxkIQ==").unwrap();

// URL-safe
let url_safe = general_purpose::URL_SAFE_NO_PAD.encode(b"Hello+World");

Data URIs

Data URIs embed file contents directly in HTML or CSS:

data:[<mediatype>][;base64],<data>
<!-- Inline PNG -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..." alt="Logo">

<!-- Inline SVG -->
<img src="data:image/svg+xml;base64,PHN2ZyB4bWxuczp4bG..." alt="Icon">

<!-- Inline font in CSS -->
@font-face {
  font-family: "CustomFont";
  src: url("data:font/woff2;base64,d09GMgABAAA...") format("woff2");
}

When to use data URIs:

  • Small images (< 2 KB) that would otherwise cause an HTTP request
  • Critical above-the-fold images in SSG/SSR pages
  • SVG icons inlined in CSS for zero request overhead

When not to use data URIs:

  • Large images — 33% overhead compounds with size; a 100 KB PNG becomes 137 KB
  • Images shared across pages — no browser caching between pages
  • Images that should be lazy loaded

HTTP Basic Authentication

HTTP Basic Auth Base64-encodes username:password in the Authorization header:

Authorization: Basic dXNlcjpwYXNzd29yZA==

Decoded: user:password

This is not encryption. The credentials are fully recoverable by anyone who intercepts the header. Always use HTTPS with Basic Auth.

MIME Email Encoding

SMTP transfers email over text channels. MIME encodes attachments using Base64:

Content-Type: application/pdf; name="report.pdf"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="report.pdf"

JVBERi0xLjQKJeLjz9MKNiAwIG9iago8PAovVHlwZSAvUGFnZQovUGFyZW50IDEgMCBSCi9N
ZWRpYUJveCBbMCAwIDYxMiA3OTJdCi9Db250ZW50cyA3IDAgUgo+PgplbmRvYmoK...

MIME Base64 wraps lines at 76 characters — a requirement that browser btoa() and most Base64 libraries do not apply by default.

JWT and Base64URL

JSON Web Tokens consist of three Base64URL-encoded segments:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMifQ.signature

To decode the payload (middle segment):

function decodeJwtPayload(token) {
  const [, payload] = token.split(".");
  // Restore standard Base64 from URL-safe
  const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
  // Add padding
  const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
  return JSON.parse(atob(padded));
}

Use the JWT Decoder Tool for quick inspection without writing code.

Performance and Size Impact

Base64 encoding always increases size by exactly 4/3 (≈ 33.3%):

OriginalBase64 Size
3 bytes4 chars (4 bytes)
1 KB1.37 KB
100 KB137 KB
1 MB1.37 MB

Combined with gzip/brotli compression, Base64-encoded content compresses better than binary (text compresses better than binary in LZ-based algorithms), partially offsetting the overhead. Base64 in gzip is approximately 10–15% larger than raw binary in gzip.

Security Considerations

  • Base64 is not encryption — it provides zero confidentiality
  • Never use Base64 to "obscure" passwords, API keys, or sensitive data in client-side code
  • The Authorization: Basic header requires HTTPS
  • Base64-encoded data in URLs (query params) is visible in server logs and browser history

Tools