Skip to content
Free Tool Arena

Developers & Technical · Guide · Developer Utilities

How to encode and decode Base64

What Base64 is (not encryption), the 3-to-4 encoding mechanics, standard vs URL-safe vs MIME variants, 33% overhead, when to use it, common mistakes, and JWT structure.

Updated April 2026 · 6 min read

Base64 is the Swiss Army knife of “I need to stuff arbitrary bytes into a text-only channel.” Email attachments, JWT tokens, data URIs in CSS, API auth headers — all lean on it. This guide walks through what Base64 actually does (spoiler: not encryption), when to use it, the variants you’ll run into (standard, URL-safe, MIME), the 33% size overhead, and the common mistakes — using it for security, forgetting to handle padding, and confusing encoding directions.

Advertisement

What Base64 is — and isn’t

Base64 is a binary-to-text encoding. It represents binary data using 64 ASCII characters (A-Z, a-z, 0-9, +, /) plus = for padding. Every 3 bytes of input become 4 characters of output.

It is NOT encryption. Anyone can decode Base64 instantly with any decoder. Treating “base64-encoded” as “obfuscated” or “secure” is a classic mistake in audits and security reviews.

It is NOT compression. Base64 expandsdata by ~33%. Encoding compressed data (like a zip file) in Base64 makes it larger, not smaller.

The entire purpose of Base64 is to let binary data travel through systems that assume text — HTTP headers, JSON values, email bodies, URL parameters, XML.

The encoding mechanics — how 3 → 4

Input: 3 bytes (24 bits).

Split those 24 bits into 4 groups of 6 bits each.

Each 6-bit group maps to one of 64 characters (hence “Base 64”).

Output: 4 characters, all printable ASCII, safe to transmit anywhere.

If input isn’t a multiple of 3 bytes, pad with zero bits and indicate with =:

1 byte of input: 2 chars of output + “==”.

2 bytes of input: 3 chars of output + “=”.

3 bytes of input: 4 chars, no padding.

This is why Base64 strings always end with 0, 1, or 2 equals signs. Length is always a multiple of 4.

Base64 variants

Standard Base64 (RFC 4648): uses + and / as the 63rd and 64th characters. Padding with =. Works for most contexts.

URL-safe Base64 (RFC 4648 §5): uses - (minus) instead of + and _ (underscore) instead of /. Padding optional. Used in JWT tokens, URL path parameters, anywhere + and / would be URL-encoded or confused with query separators.

MIME Base64 (RFC 2045): standard Base64 with line breaks every 76 characters. Used in email attachments.

Base64 without padding: some formats (JWT) strip trailing = for compactness. Decoders must handle both padded and unpadded input.

Mixing variants is a common bug source: a decoder expecting standard Base64 chokes on URL-safe input containing - or _. Know which variant you’re in.

The 33% size overhead

Output size = ⌈input_bytes / 3⌉ × 4.

100 bytes of input → 136 bytes of output (36% larger when padding counts).

1 KB → ~1.33 KB.

1 MB → ~1.33 MB.

Implication: inlining images as data URIs (“data:image/ png;base64,...”) adds 33%. For a 1 MB hero image, that’s 333 KB extra payload the browser has to parse before it can display anything. Small icons: fine. Large images: bad tradeoff.

When to use Base64

Email attachments. SMTP historically supported only 7-bit ASCII. MIME Base64 remains the standard.

HTTP Basic Auth headers.“Authorization: Basic <base64(user:password)>”. Remember — this is encoding, not security. Basic Auth without TLS is plaintext.

JWT tokens. JSON Web Tokens are three URL-safe-Base64 segments separated by dots: header.payload.signature.

Data URIs. “data:image/png;base64,...” embeds binary assets inline in HTML/CSS. Use for small icons, SVG fallbacks.

API responses with binary data. When JSON needs to contain an image, file, or cryptographic key, Base64 it.

Storing binary in databases with text-only columns.Better practice is to use a binary column (BLOB, BYTEA), but Base64 in a VARCHAR works when you can’t.

When NOT to use Base64

Hiding sensitive data. It’s trivially reversible. Use real encryption (AES, RSA, etc.), not Base64.

Large file transfer. The 33% overhead and text-parsing cost make it wasteful compared to binary protocols. Stream the binary directly.

Database primary keys. Sort order is funky, prefix indexing is weird. Use binary columns or hex encoding instead.

Large inline images. As above — 33% size penalty is real. Use a regular image file or a CDN.

Common mistakes

1. Treating Base64 as security. “We obfuscated the API key with Base64” is a red flag. It takes 1 second to decode.

2. URL-breaking with + and /. Passing standard Base64 in a URL query parameter: + becomes space, / can confuse path parsers. Use URL-safe Base64 or URL-encode the whole string.

3. Assuming Base64 is the input. Double- encoding happens when a pipeline encodes already-encoded data. The result decodes to a Base64 string, not the original.

4. Stripping padding then feeding to strict decoder. A decoder without tolerant mode needs the = back. Add padding: string + “=” × ((4 − length mod 4) mod 4).

5. Encoding text with the wrong charset.Base64 encodes bytes, not characters. If the string is UTF-8, encode the UTF-8 byte representation, not the code points. Different languages handle this differently; test with non-ASCII data.

Encoding and decoding in different languages

JavaScript (browser): btoa() for encode, atob() for decode. Gotcha: these only work for Latin-1 strings — for UTF-8, wrap with encodeURIComponent/decodeURIComponent dance, or use TextEncoder + Uint8Array.

Node.js: Buffer.from(s, ‘utf8’).toString(‘base64’) to encode; Buffer.from(s, ‘base64’).toString(‘utf8’) to decode.

Python: base64.b64encode(bytes) and base64.b64decode(string). Use base64.urlsafe_b64encode for URL-safe variant.

CLI (Linux / macOS): echo “hello” | base64 to encode; echo “aGVsbG8K” | base64 -d to decode.

JWT — the example everyone sees

A JWT looks like xxxxx.yyyyy.zzzzz. Each segment is URL-safe Base64 without padding.

Decode any segment with a Base64 decoder and you’ll see the JSON. The payload is readable by anyone — never put secrets in a JWT payload. The signature (third segment) authenticates the token; anyone can read the contents, but only the holder of the signing key can forge one.

Run the numbers

Encode or decode Base64 with the Base64 encoder/decoder. Pair with the JWT decoder when inspecting tokens (which are URL-safe Base64 under the hood), and the URL encoder/decoder for the next-layer URL-percent-encoding you often need alongside Base64.

Advertisement

Found this useful?Email