# Base64

> Encode or decode Base64, standard or URL-safe, with proper UTF-8 handling.

Category: Encoding · Page: https://util.caruana.me/tools/base64/

## API, MCP and A2A

### Base64: Encode (`base64_encode`)

`GET|POST https://util.caruana.me/api/base64/encode` · MCP tool `base64_encode` · A2A skill `base64_encode` · [reference](https://util.caruana.me/reference/base64_encode/)

Encodes the UTF-8 bytes of `input`. `standard` uses `+/` with `=` padding; `url` uses `-_` without padding.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `input` | string | yes | Text to convert. As a `text/plain` POST body it is used verbatim. |
| `mode` | standard \| url | no | `standard`: RFC 4648 §4 — A–Z a–z 0–9 + / with = padding. `url`: RFC 4648 §5 — - and _ instead of + and /, no padding (JWT style) |

Privacy: The server receives the `input` text and `mode`, converts it in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. Send secrets in a POST body, not the query string: URLs are recorded in Cloudflare request logs, proxies, and shell history.

### Base64: Decode (`base64_decode`)

`GET|POST https://util.caruana.me/api/base64/decode` · MCP tool `base64_decode` · A2A skill `base64_decode` · [reference](https://util.caruana.me/reference/base64_decode/)

Accepts either alphabet, with or without padding, and ignores whitespace. `mode` does not change decoding.

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `input` | string | yes | Text to convert. As a `text/plain` POST body it is used verbatim. |
| `mode` | standard \| url | no | `standard`: RFC 4648 §4 — A–Z a–z 0–9 + / with = padding. `url`: RFC 4648 §5 — - and _ instead of + and /, no padding (JWT style) |

Privacy: The server receives the `input` text and `mode`, converts it in memory inside the request, and returns the result. Your input is not stored or logged; only the per-call metadata row (operation, time, status, sizes) is recorded. Send secrets in a POST body, not the query string: URLs are recorded in Cloudflare request logs, proxies, and shell history.


## User guide

The tool sits in a window that works like a desktop app: menus on the top row and the **full-screen** icon at its right (**Esc** leaves full screen). The set-up options described below are in **Settings → Options…**, an overlay, and the **Settings** menu also lists the common choices directly. To keep the options in view instead, choose **View → Inline config**; the page remembers that choice. **Help → Keyboard shortcuts…** lists the keys.

1. Choose **Encode** or **Decode**.
2. For encoding, choose **Standard** (the usual choice, for MIME, data: URLs and PEM bodies) or **URL-safe** (for JWTs, URL parameters and file names).
3. Type or paste your input. The output updates as you type.

**Decoding is forgiving.** The decoder accepts either alphabet, with or without `=` padding, and ignores spaces and line breaks. That means you can paste a wrapped PEM body or a JWT segment directly. The mode buttons only affect encoding.

**"Decoded bytes are not valid UTF-8 text".** The Base64 is valid, but it encodes binary data (an image, a key, compressed data) rather than text, and this tool only displays text. To check the bytes, use the [Hex](/tools/hex/) tool on the same data, or the API's `/api/hash` with `input_base64`.

## Specification

- **Standards.**
  - **Standard mode:** RFC 4648 §4 (`A–Z a–z 0–9 + /`, padded with `=`).
  - **URL-safe mode:** RFC 4648 §5 (`-` and `_` in place of `+` and `/`, no padding: the JWT/RFC 7515 convention).
- **Text handling.** Input text is encoded as UTF-8 before Base64 encoding, so `é` (U+00E9) becomes bytes `C3 A9` and then `w6k=`. The browser's `btoa` on its own would throw on non-Latin-1 text; this tool doesn't.
- **Decoding rules.**
  1. Remove all whitespace.
  2. Map `-` → `+` and `_` → `/`.
  3. Reject any character outside the alphabet, and padding that isn't at the end.
  4. Reject a length ≡ 1 (mod 4), which can never be valid.
  5. Restore missing padding.
  6. Decode the bytes as UTF-8 in **fatal** mode: invalid UTF-8 is an error, never silently replaced with `�`.
- **Line wrapping.** Encoded output is never wrapped. MIME's 76-character lines and PEM's 64-character lines are not added.
- **Limits.** Browser memory only. The API accepts up to 1 MiB, and encodes in 32 KiB chunks to avoid call-stack limits.
