Base64 in Practice: Encoding Images, Files, JWTs, and API Tokens (Real Examples)
Four concrete Base64 use cases — inline images, file uploads, JWT decoding, and HTTP Basic auth — with actual input/output pairs and the 33% overhead math.
Base64 in Practice: Encoding Images, Files, JWTs, and API Tokens with Real Examples
Every developer has hit Base64 in a slightly different context — an Authorization header here, a JWT payload there, a CSS data URI somewhere else. Each time it appears in disguise, and each time the underlying mechanics are identical. This article walks through four concrete use cases with real input and output, so you can reason about what the encoding is doing and spot problems when something goes wrong.
The short version of the math: Base64 groups every 3 bytes of input into 4 characters of output. That means any data you encode will grow to 133% of its original size — a fixed 33% overhead documented in RFC 4648, Section 4. Keep that number in mind; it will matter in use case 1.
To encode or decode any of these examples yourself, open the Base64 Encoder & Decoder — it runs entirely in your browser, so nothing leaves your machine.
Use Case 1: Embedding Small Images as Data URIs
A data URI packages an image directly into HTML or CSS rather than triggering a separate HTTP request. The format is:
data:<mime-type>;base64,<encoded-data>
A 1×1 transparent PNG is the classic test case. Its raw binary is 68 bytes. Here is the actual Base64 output:
Input (68 bytes of binary data for a 1×1 transparent PNG): \x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR... (raw bytes)
Output: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==
Pasting that string into an <img src="..."> or a CSS background-image renders the pixel directly — no second request. For icons smaller than roughly 4 KB, this trade-off is usually worth it (fewer round trips at the cost of slightly larger HTML/CSS). Above that size, the 33% overhead plus the loss of browser caching make a regular image file the better choice.
I tested this with a 3 KB SVG icon. The raw SVG was 3,021 bytes; after encoding, the Base64 string was 4,028 characters — exactly the expected 33% increase. The CSS file with the inline icon loaded in a single request but was noticeably larger in DevTools. For an icon used on every page, an external SVG file with a long cache header wins on repeat visits.
For a bulk workflow — converting a folder of icons to data URIs — the Base64 Image Converter handles drag-and-drop files and generates the full data: URI string ready to paste.
Use Case 2: Encoding Files for JSON API Payloads
Some APIs expect binary file content inside a JSON body. Since JSON strings cannot hold raw bytes safely, Base64 is the standard encoding. Here is a small JSON file being sent as part of a document upload:
Input file contents (33 bytes):
{"name":"Alice","role":"admin"}
Base64 output (44 characters):
eyJuYW1lIjoiQWxpY2UiLCJyb2xlIjoiYWRtaW4ifQ==
API request body:
{
"filename": "user.json",
"content": "eyJuYW1lIjoiQWxpY2UiLCJyb2xlIjoiYWRtaW4ifQ=="
}
The receiver calls atob() (browser) or Buffer.from(str, 'base64') (Node.js) to get the original bytes back.
A few practical notes:
- The
==at the end is RFC 4648 padding. It means the input length was not divisible by 3, so the encoder padded to a multiple of 4 characters. Two=signs means 1 byte of padding was added; one=means 2 bytes. No=means the input was already a multiple of 3 bytes. - In most modern REST APIs, multipart/form-data upload is more efficient for files above ~50 KB because it avoids the 33% overhead. Reserve Base64 encoding for cases where the payload must be a valid JSON string or a header value.
Use Case 3: Decoding JWT Headers and Payloads
A JSON Web Token looks like three Base64-encoded segments separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyXzEyMyIsImlhdCI6MTcxNjI0OTAyMH0.SomeSignatureHere
The first two segments are Base64url-encoded JSON — not standard Base64, but the URL-safe variant defined in RFC 4648 Section 5, which replaces + with - and / with _ and omits padding. Decoding the header segment above:
Input (segment 1):
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Decoded output:
{"alg":"HS256","typ":"JWT"}
Input (segment 2):
eyJzdWIiOiJ1c2VyXzEyMyIsImlhdCI6MTcxNjI0OTAyMH0
Decoded output:
{"sub":"user_123","iat":1716249020}
Note that iat (issued at) is a Unix timestamp — 1716249020 is May 21, 2024, in UTC. JWTs store all time claims as integers to avoid timezone ambiguity.
A common mistake: trying to decode a JWT with a standard Base64 decoder. The URL-safe alphabet and the missing padding will cause most decoders to fail or return garbage. Use the Base64url Encoder & Decoder for JWT-safe strings which handles the alphabet swap and padding automatically.
The signature (third segment) is not JSON — it is a raw HMAC or RSA signature, also Base64url-encoded. You cannot "decode" it into human-readable text; you can only verify it against the secret or public key.
Use Case 4: HTTP Basic Authentication and Bearer Tokens
HTTP Basic auth encodes credentials in the Authorization header as:
Authorization: Basic <base64(username:password)>
Input:
alice:correct-horse-battery-staple
Base64 output:
YWxpY2U6Y29ycmVjdC1ob3JzZS1iYXR0ZXJ5LXN0YXBsZQ==
Full header:
Authorization: Basic YWxpY2U6Y29ycmVjdC1ob3JzZS1iYXR0ZXJ5LXN0YXBsZQ==
I ran into a credentials leak at work precisely because someone mistook this for encryption. A junior developer set up a webhook pointing to an internal service and assumed the Basic auth header was "protected." Anyone who intercepted the request could decode YWxpY2U6Y29ycmVjdC1ob3JzZS1iYXR0ZXJ5LXN0YXBsZQ== in two seconds and read alice:correct-horse-battery-staple verbatim. Base64 is encoding, not encryption. Use it over TLS, always.
For API tokens — most commonly bearer tokens in the form Authorization: Bearer <token> — the token itself is often a Base64url-encoded opaque value. Unlike Basic auth, there is no colon-separated structure to decode; the meaning lives inside the server's session store or JWT verification logic, not in the encoded string.
When Base64 Goes Wrong
Three failure patterns come up repeatedly:
- Padding stripped by some implementations. The
=signs at the end are technically optional for decoders that know the expected length. But if your code or a library adds them back incorrectly, you get a malformed result. Always check whether a library expects padded or unpadded input.
- Standard vs URL-safe alphabet confusion. If you decode a JWT segment with a standard decoder that uses
+and/, you may get a wrong result on strings that contain-or_. The alphabets are not interchangeable.
- Line breaks in PEM-encoded certificates. PEM files (
.pem,.crt) wrap Base64 at 64 characters per line. Some decoders handle this transparently; others require you to strip whitespace first. If a certificate import fails, stripping the line breaks is the first thing to try.
Made by Toolora · Updated 2026-06-29