How Does Base64 Work
Base64 converts binary data into text so it can travel through channels that only handle characters. RFC 4648 defines the mechanism: every 3 bytes — 24 bits — become 4 characters from a 64-symbol alphabet, with = padding when the bytes do not divide evenly. It grows data by about a third and is an encoding, not encryption.
How Does Base64 Work explained
Email systems of the 1980s moved 7-bit text and nothing else; HTTP headers, JSON fields, URLs and log files are text-only territories in practice. Raw binary — an image, a signature, a cryptographic key — corrupts the moment such a channel meets it. Base64 is the standard bridge: a fully reversible way to spell arbitrary bytes using nothing but 64 safe printable characters.
You have read Base64 all day without noticing it: every JWT is three Base64url segments, every data: URI embedded in CSS, every MIME email attachment. The scheme is specified in RFC 4648 — which consolidated the earlier Base-64 definitions into one document — and it is small enough to compute by hand. This guide does exactly that, one 24-bit group at a time.
Three things confuse everyone at first: why 3 bytes become 4 characters, what the = signs are for, and why there are two alphabets. Each gets its own section below, along with the honest limits — the size penalty, the whitespace disagreements between decoders, and the persistent mistake of treating a reversible encoding as security.
Reading beats describing here — paste any string into the Base64 decoder and watch the bytes it hides; it decodes locally, so tokens and keys stay in your tab.
The most famous Base64 consumer is the token format; the JWT structure guide shows how a JWT's three segments ride on the URL-safe alphabet defined below.
The mechanism: 3 bytes in, 4 characters out
Take any binary data and slice it into groups of 3 bytes — 24 bits. Split each group into four 6-bit chunks. Each chunk is a number from 0 to 63, and the RFC 4648 alphabet maps those numbers onto characters: A–Z for 0–25, a–z for 26–51, 0–9 for 52–61, then + and / for 62 and 63. Six bits is the sweet spot because 2⁶ = 64 is exactly the size of an alphabet that every character-only channel can carry without complaint.
The classic worked example is the RFC's own test vector, the word Man — three bytes, no padding needed:
Byte by byte
M 0x4D 01001101 a 0x61 01100001 n 0x6E 01101110 joined: 010011 010110 000101 101110 indexes: 19 22 5 46
Character by character
19→T 22→W 5→F 46→u "Man" → TWFu "Ma" → TWE= "M" → TQ==
Padding: what the = signs mean
Six-bit chunks only reassemble into bytes in whole groups of four. When the input length is not a multiple of 3, the final group comes up short: 2 remaining bytes produce three characters plus one = sign, and 1 remaining byte produces two characters plus ==. Padding restores the length so a decoder can compute the exact byte count without guessing — and = is the only character outside the 64-symbol alphabet that may appear in the output.
Padding is length metadata, not security or compression. RFC 4648 permits unpadded variants when both sides agree — the Base64url of JWTs notably drops the = entirely, because the dots delimit segments and each segment's length tells the decoder everything it needs.
| Input bytes | Output characters | Padding | Example |
|---|---|---|---|
| 3 (any multiple of 3) | 4 per 3 bytes | none | "Man" → TWFu |
| 2 | 3 | one = | "Ma" → TWE= |
| 1 | 2 | two == | "M" → TQ== |
| 12 | 16 | none | "Hello, world" → SGVsbG8sIHdvcmxk |
The two alphabets: standard and URL-safe
The standard alphabet uses + and / — harmless in email, hostile in URLs, where + decodes as a space and / as a path separator. RFC 4648 §5 therefore defines Base64url, replacing + with - and / with _: characters that need no percent-encoding inside URLs and no quoting inside filenames or cookies. The two dialects are otherwise identical — same 6-bit chunks, same padding rules.
That is the practical trap: the dialects differ in only two characters, so a token pasted with the wrong alphabet fails two characters in — or worse, decodes to different bytes if it happens to contain + or /. Well-behaved decoders accept either form and tell you which they saw; strict ones refuse mixed alphabets outright rather than guess.
| Values | Standard | URL-safe |
|---|---|---|
| 0–25 | A–Z | A–Z |
| 26–51 | a–z | a–z |
| 52–61 | 0–9 | 0–9 |
| 62 | + | - |
| 63 | / | _ |
Same bytes, two dialects
bytes: 0xFB 0xEF 0xBE standard: ++++ url-safe: ----
Where the dialects bite
in a URL query, ++++ arrives as four spaces (plus-to-space rule) — ---- arrives intact. This is why tokens use the URL-safe alphabet.
Size: the one-third tax and its fine print
Four characters carry three bytes, so encoded output is always 4/3 of the input — about a 33% increase — before any transport overhead. For concrete anchors: 100 bytes encode to 136 characters, 17 bytes to 24, and the ratio never moves, because it is arithmetic rather than tuning. Padding, line breaks and wrapping add more: MIME caps Base64 lines at 76 characters and requires CRLF breaks between them, which contributes a little extra on large payloads. A data: URI embeds that already-inflated form inside CSS or HTML, which is why inlined images weigh roughly a third more than the binary files they replace.
Nothing reversible shrinks data, and Base64 is no exception — it is a spelling change, not compression. If size matters, compress first and encode the compressed bytes; never the reverse order.
Whitespace, line breaks and decoder disagreements
RFC 4648 is strict: decoders must reject characters outside the alphabet, and the document itself says nothing about requiring line breaks. MIME's Base64 (RFC 2045) expects the opposite — CRLF every 76 characters. Real implementations scatter between the poles: many strip whitespace silently, some insist on it, some reject any newline at all. This is the classic reason a string that 'encodes fine' in one tool fails to decode in another.
The honest interoperability rule: produce standard, padded, unwrapped Base64 unless a specification says otherwise, and build decoders that tolerate the whitespace other tools add — while still refusing any character that is not part of a recognised alphabet, because leniency there is how silent byte corruption begins.
What Base64 is not
Base64 has no key, no rounds of mixing, no secret: anyone can reverse it, and decoders ship in every language's standard library. Treating an encoded payload as protected data is a recurring vulnerability report. The give-aways are public: SGVsbG8= spells Hello, JVBERi0x opens a PDF, /9j/ begins a JPEG, and eyJ begins almost every JSON Web Token — those first characters are simply Base64 for %PDF-, the JPEG magic bytes, and a JSON opening brace.
Use Base64 for what it is: a container-safe spelling of bytes. Put confidentiality in real encryption — TLS in transit, a proper cipher at rest — and keep Base64 as the final step that makes the result printable, nothing more.
Telltale openings
SGVsbG8sIHdvcmxk JVBERi0xLjQ= /9j/ eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
What they decode to
Hello, world
%PDF-1.4
(bytes FF D8 FF — a JPEG's magic number)
{"alg":"HS256","typ":"JWT"}Frequently asked questions
Is it safe to paste tokens and keys into a Base64 decoder?
On this site, yes: the decoder runs in your browser and never transmits your input — there is no upload endpoint to leak from. The Network panel shows no requests while you decode, and the site's Content-Security-Policy blocks outbound connections. It matters because Base64 tokens are live credentials, and many random web decoders are far less careful about what happens to them.
Is Base64 encryption?
No — it is an encoding with no key and no secrecy property. Any library, and any attentive human, can reverse it instantly; an encoded password is a visible password. Encryption transforms data so it is unreadable without a key, while Base64 only re-spells bytes so text-only channels can carry them. The two solve different problems and often appear together.
Why does Base64 output end with = signs?
The = is padding that restores length. Output comes in 4-character groups, and when the input was not a multiple of 3 bytes the final group is topped up — one = for two leftover bytes, two for one, never three, because a complete group needs none. The signs carry no data; they tell the decoder the exact byte count.
What is the difference between Base64 and Base64url?
Two characters. Base64url, defined in RFC 4648 §5, replaces + with - and / with _ so output is safe in URLs, filenames and cookies without escaping. Everything else — the 6-bit grouping, the letters and digits, the padding rules — is identical, and formats such as JWTs use the URL-safe variant with padding removed.
Why is Base64 output bigger than its input?
Each output character carries 6 bits while a byte carries 8, so 3 bytes — 24 bits — require 4 characters: a fixed 4/3, or roughly 33% overhead, before padding and line breaks. It is the price of staying printable; no reversible encoding avoids it, which is why raw binary transport wins wherever the channel permits actual bytes.
Can I decode Base64 by hand?
Yes — the design invites it. Write the input's bytes in binary, regroup each 24-bit block into four 6-bit chunks, and read each chunk off the alphabet table: A=0 through Z=25, a=26 through z=51, 0=52 through 9=61, then + and /. The RFC's own example works on paper: Man is 010011 010110 000101 101110, which reads T, W, F, u — TWFu.
Which related tools should I use next?
- Base64 Decode & EncodeDecode and encode standard and URL-safe Base64, with binary download.Open
- Encoding ToolsBase64, URL encoding, hashing and token inspection.Open
- JWT StructurePlain-English guideOpen
- UUID VersionsPlain-English guideOpen
- JWT DecoderDecode a JSON Web Token and see what every claim means.Open
- JSON ToolsCompare, format, validate and explore JSON documents.Open