If you've ever inspected a JWT token, decoded a data URI for an image, or set up HTTP Basic Auth, you've encountered Base64. It appears in countless corners of modern web development, yet many developers have only a fuzzy understanding of what it actually does and why it exists. This guide explains Base64 from first principles.
The Problem Base64 Solves
Binary data — such as images, audio files, PDFs, or cryptographic keys — contains arbitrary byte values, including bytes that represent control characters in older text protocols (like carriage returns, null bytes, and byte-order marks). Many text-based protocols including SMTP (email), HTTP/1.1 headers, and URLs were designed to handle only printable ASCII text. If you try to embed raw binary data in these contexts, it gets corrupted.
Base64 solves this by converting binary data into a string of 64 universally safe ASCII characters, allowing arbitrary binary data to be transmitted reliably over any text-based channel.
How Base64 Encoding Works
Base64 uses an alphabet of 64 characters: the uppercase letters A–Z, lowercase letters a–z, digits 0–9, and two special characters + and /. The = character is used as padding.
The encoding process works in three steps:
- Group bytes into triplets. Take the input bytes three at a time. Three bytes = 24 bits.
- Split each triplet into four 6-bit groups. 24 bits ÷ 6 = four 6-bit values (each 0–63).
- Map each 6-bit value to a Base64 character. Value 0 =
A, value 1 =B, ..., value 63 =/.
Input: M a n ASCII: 77 97 110 Binary: 01001101 01100001 01101110 Group into 6-bit chunks: 010011 010110 000101 101110 Map to Base64 alphabet: 19=T 22=W 5=F 46=u Result: TWFu
Note that every 3 bytes of input produce exactly 4 characters of Base64 output — a size increase of approximately 33%.
The Padding Character (=)
Base64 works in groups of 3 bytes. If the input length isn't divisible by 3, padding is added:
- If the input has 1 remaining byte after processing full triplets, 2
=characters are appended. - If the input has 2 remaining bytes, 1
=character is appended.
This is why Base64 strings often end with one or two = signs — it's just structural padding, not meaningful data.
When and Where Is Base64 Used?
- Data URIs — Embed images directly in HTML or CSS without a separate HTTP request:
<img src="data:image/png;base64,iVBORw0KGgo..."> - JSON Web Tokens (JWTs) — The header and payload of a JWT are Base64URL-encoded JSON objects. Base64URL is a variant that replaces
+with-and/with_and omits=padding, making it safe to use directly in URLs. - HTTP Basic Authentication — Credentials are sent as
Authorization: Basic <base64(username:password)>. The server decodes the Base64 string to extract the username and password. - Email Attachments (MIME) — Email protocols like SMTP are text-based. File attachments are Base64-encoded before being embedded in the email body.
- Storing Binary Data in JSON — Since JSON has no binary type, binary data (like encrypted values or image thumbnails) is Base64-encoded before being stored in a JSON field.
- Cryptographic Keys and Certificates — PEM files (used for SSL certificates and private keys) use Base64 to encode binary DER data between
-----BEGIN CERTIFICATE-----markers.
Base64 is NOT Encryption
This is critically important: Base64 is an encoding, not encryption. It provides zero security. Anyone who receives a Base64-encoded string can trivially decode it. The Base64 in a JWT's payload is entirely readable by anyone — the JWT's security comes from the signature, not the encoding.
Never use Base64 to "hide" sensitive data. Use actual encryption (AES, RSA) for confidentiality and HTTPS for transport security.
Base64 in PHP and JavaScript
// Encode
$encoded = base64_encode('Hello, World!');
// → SGVsbG8sIFdvcmxkIQ==
// Decode
$decoded = base64_decode('SGVsbG8sIFdvcmxkIQ==');
// → Hello, World!
// For URLs, use base64url (replaces +/= for URL safety)
$urlSafe = rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
// Encode a string to Base64
const encoded = btoa('Hello, World!');
// → SGVsbG8sIFdvcmxkIQ==
// Decode Base64 to a string
const decoded = atob('SGVsbG8sIFdvcmxkIQ==');
// → Hello, World!
// Note: btoa/atob only handle Latin-1 characters.
// For full Unicode support, encode as UTF-8 first:
const utf8Encoded = btoa(encodeURIComponent('Héllo Wörld'));
const utf8Decoded = decodeURIComponent(atob(utf8Encoded));
Encode & Decode Base64 Instantly
No code needed — use our free tools to encode any text to Base64 or decode Base64 strings back to readable text.