{ }jsonkitOpen the tool

Base64 Encoding Explained: What It Is and How It Works

8 min read · updated 2026-07-12

Base64 shows up everywhere once you start looking: data: URLs embedding an image, a JWT payload, an email attachment, an API key baked into a config. All of them use the same trick — representing arbitrary binary data as plain ASCII text so it can travel safely through systems that only expect text.

This guide explains Base64 from first principles: the problem it solves, the exact algorithm that turns three bytes into four characters, the standard and URL-safe alphabets defined by RFC 4648, what the = padding is for, and the single most important thing to understand — Base64 is an encoding, not encryption. It hides nothing.

The Problem Base64 Solves

Computers store everything as bytes — sequences of 8 bits that can hold any value from 0 to 255. Text is just one interpretation of those bytes. Many systems, though, were built to move *text* around: email bodies, URLs, JSON strings, XML documents, HTTP headers. Hand them raw binary — the bytes of a PNG, a compressed archive, an encryption key — and things break. A null byte can truncate a string; a byte that happens to match a control character can be mangled; anything outside the printable ASCII range may not survive the trip.

Base64 sidesteps the whole problem by re-expressing binary data using only 64 characters that every text system agrees on: A–Z, a–z, 0–9, and two symbols. The result is a string that looks like gibberish but is guaranteed to be safe printable text. You can drop it into a JSON value, a URL, or an email and be confident it arrives byte-for-byte intact.

How Base64 Actually Works

The name is the algorithm: work in base 64. Take the input as a stream of bits and regroup it. Binary is 8 bits per byte; Base64 is 6 bits per character (because 2^6 = 64). The least common multiple of 8 and 6 is 24, so Base64 processes the input 3 bytes (24 bits) at a time and emits 4 characters (24 bits).

Walk through encoding the word Man. Its three ASCII bytes are 77, 97, 110, which in binary is 01001101 01100001 01101110. Line those 24 bits up and re-slice them into four 6-bit groups:

Encoding 'Man' — 3 bytes become the 4 characters 'TWFu'.text
Text:     M          a          n
ASCII:    77         97         110
Bits:     01001101   01100001   01101110
Regroup:  010011  010110  000101  101110
Value:    19      22      5       46
Base64:   T       W       F       u

Each 6-bit value (0–63) is an index into the Base64 alphabet. Index 19 is T, 22 is W, 5 is F, 46 is u — so Man encodes to TWFu. Decoding just reverses the process: map each character back to its 6-bit value, concatenate the bits, and re-slice into 8-bit bytes.

Base64 in JavaScript — and the UTF-8 caveat for non-ASCII text.js
// In the browser (and modern Node):
const encoded = btoa("Man"); // "TWFu"
const decoded = atob("TWFu"); // "Man"

// Note: btoa/atob work on binary strings, not Unicode text.
// For arbitrary strings, encode to UTF-8 bytes first:
const bytes = new TextEncoder().encode("café");
const b64 = btoa(String.fromCharCode(...bytes)); // "Y2Fmw6k="

Padding: What the '=' Means

Base64 works in 3-byte groups, but real data rarely divides evenly by three. When the final group has only 1 or 2 bytes left over, the encoder pads the output to a multiple of four characters using the = sign. = is never a data character — it exists purely to signal how many bytes the last group actually held.

  • 3 bytes left → 4 characters, no padding (e.g. TWFu).
  • 2 bytes left → 3 characters + one = (e.g. TWE= for Ma).
  • 1 byte left → 2 characters + two = (e.g. TQ== for M).

Because the count of = tells the decoder exactly how many trailing bytes to keep, some contexts drop padding entirely to save characters — most notably JWTs and URL parameters. A compliant decoder can usually reconstruct the length without it, which is why you will see unpadded Base64 in the wild.

Standard vs URL-Safe Base64 (RFC 4648)

The canonical specification is RFC 4648. It defines two alphabets. The first 62 characters are identical in both — A–Z, a–z, 0–9. The disagreement is only about the last two symbols and the padding, and it matters enormously depending on where the string will live.

Index 62Index 63PaddingSafe in URLs?
Standard Base64+/=No
URL-safe Base64-_often omittedYes

Standard Base64 uses + and /. Both are problematic in a URL: + is interpreted as a space in query strings, and / is a path separator. The URL-safe variant swaps them for - (hyphen) and _ (underscore), neither of which needs escaping in a URL or filename. Padding = is also reserved in URLs, so URL-safe Base64 commonly drops it.

Converting between the two is a simple character swap: replace +- and /_ (and strip =) to go URL-safe, and reverse it to go back. If a decoder rejects a string, a mismatched alphabet is one of the first things to check.

b64Base64 Encode / DecodeOpen the tool

Base64 Is Not Encryption

This is the single most common misconception, and it has real security consequences. Base64 is a reversible, public, keyless transformation. Anyone can decode any Base64 string instantly — there is no secret involved. It provides zero confidentiality. Encoding a password, an API secret, or personal data in Base64 does *not* protect it; it only makes it slightly less obvious to a human skimming the text.

Base64 offers no secrecy — decoding needs no key.js
// "Encoding" a secret protects nothing:
const secret = btoa("hunter2"); // "aHVudGVyMg=="
atob("aHVudGVyMg=="); // "hunter2" — trivially reversed by anyone

The distinction: encoding changes the representation of data for compatibility (Base64, URL-encoding, UTF-8); encryption protects data so only holders of a key can read it (AES, RSA). If you need confidentiality, you need encryption. Use Base64 only for what it is for — moving binary safely through text channels.

Where You'll Actually Meet Base64

  • Data URLsdata:image/png;base64,iVBORw0KGgo... embeds an image directly in HTML or CSS, no separate request.
  • JWTs — the header and payload are Base64URL-encoded JSON; see our JWT guide.
  • Email (MIME) — attachments and non-ASCII bodies are Base64-encoded so they survive text-only mail transport.
  • HTTP Basic Auth — the Authorization header carries base64(username:password) (which is exactly why Basic Auth requires HTTPS).
  • Binary in JSON — JSON has no binary type, so a byte blob is stored as a Base64 string field.

That last case is the one JSON developers hit most: since JSON has no native binary type, any file bytes, hash, or key you want to embed in a payload has to become a Base64 string first, then get decoded on the other side.

Whenever you need to inspect a token, embed an asset, or verify what a Base64 string actually contains, decoding it locally is the fastest check. A client-side tool does the transform in your browser — nothing is uploaded — so you can paste a token or a data: URL and read the bytes without sending sensitive data anywhere.

b64Base64 Encode / DecodeOpen the tool

Frequently asked questions

Is Base64 encryption or encoding?

Encoding. Base64 is a public, reversible transformation with no key — anyone can decode any Base64 string instantly. It changes how data is represented so binary can travel safely through text channels, but it provides no confidentiality whatsoever. For secrecy you need real encryption like AES; never rely on Base64 to protect a password, token, or personal data.

Why is Base64-encoded data about 33% larger?

Base64 represents every 6 bits of input with one 8-bit character, and it processes data in 3-byte (24-bit) groups that become 4 characters. Four characters for every three bytes is a 4:3 ratio, so the encoded output is roughly 33% bigger than the original binary, before counting any padding.

What is the difference between standard and URL-safe Base64?

Both share the first 62 characters (A–Z, a–z, 0–9). Standard Base64 (RFC 4648 §4) uses + for index 62 and / for index 63, with = padding. URL-safe Base64 (§5) swaps those for - and _ so the string is safe in URLs and filenames, and it usually omits the = padding. JWTs use the URL-safe variant.

What does the '=' at the end of a Base64 string mean?

It is padding. Base64 works in 3-byte groups; when the final group has only 1 or 2 bytes, the encoder pads the 4-character output with = so the length stays a multiple of four. Two = means one leftover byte, one = means two leftover bytes. Some formats (JWTs, URLs) drop the padding since the length can be inferred.

Why can't I put raw binary directly in JSON?

JSON has only six value types — string, number, boolean, null, object, and array — and no binary type. Raw bytes can also contain characters that break string parsing. The standard workaround is to Base64-encode the bytes into a JSON string and decode them on the other side.

Does btoa in JavaScript handle Unicode text?

Not directly. btoa expects a 'binary string' where each character is a single byte (0–255), so it throws on characters above U+00FF like emoji or accented letters. Encode the text to UTF-8 bytes first — for example with TextEncoder — then Base64 those bytes. Reverse the steps when decoding.