The two-character difference
Both encodings turn 3 input bytes into 4 output characters from a 64-character alphabet. They differ on two characters:
| Position | Base64 (RFC 4648 §4) | Base64 URL (RFC 4648 §5) |
|---|---|---|
| 62 | + | - |
| 63 | / | _ |
| Padding | = required to multiple of 4 | = usually omitted |
That's it. Same 0–61 (A–Z, a–z, 0–9), same encoding algorithm, same decoded output. The two-character swap exists so the result is safe to drop into a URL path or query string without further escaping.
When to use which
Use Base64 (standard) for…
- Email attachments — MIME content-transfer-encoding has used standard Base64 for decades.
- Binary data in JSON or XML — APIs that embed images, PDFs, or other binary in a text payload almost always use standard Base64.
- Data URIs —
data:image/png;base64,...uses standard Base64. - Anything where you control the transport and don't need URL safety.
Use Base64 URL for…
- JWTs — every part of a JSON Web Token is Base64 URL encoded with padding stripped.
- OAuth 2.0 tokens, PKCE code challenges — RFC 7636 mandates Base64 URL.
- URL-safe IDs — short hashes, share links, signed cookies that travel as path or query parameters.
- WebPush keys — VAPID keys are Base64 URL by spec.
- Anywhere the encoded value is going inside a URL and you don't want to double-escape.
Why the standard Base64 characters break URLs
URLs interpret several Base64 characters as control:
-
+— inapplication/x-www-form-urlencoded(the format used by most form submissions),+means a space. So a Base64 string likeaGVsbG8+becomesaGVsbG8(with a space) when read by a server expecting form-encoded input. -
/— splits a URL path into segments. A Base64 string containing/dropped into a path will be parsed as multiple path segments. -
=— separates query keys from values. Trailing=padding can confuse query string parsers.
Base64 URL avoids all three by mapping the two problematic alphabet
characters to - and _ (which are valid in
URLs without escaping) and dropping padding entirely.
Converting between them
The transform is mechanical:
// standard → URL
const urlSafe = standard
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
// URL → standard
const padded = urlSafe + "=".repeat((4 - urlSafe.length % 4) % 4);
const standard = padded.replace(/-/g, "+").replace(/_/g, "/"); Our encoder does the conversion for you — paste a Base64 URL string into the Base64 URL tab and decode, or paste a standard Base64 string into the Base64 tab.
Quick reference: decoding a JWT
A JWT is three Base64 URL segments joined by dots:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIn0.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk To peek at the contents:
- Split on
.— three segments. - Decode segment 1 (header) as Base64 URL → JSON. Tells you the algorithm.
- Decode segment 2 (payload) as Base64 URL → JSON. Your claims.
- Segment 3 is the signature — binary, used only for verification.
Important: decoding only proves what the token claims. Always verify the signature server-side before trusting any claim from a JWT.
Reference
- RFC 4648 — Base64, Base64 URL, Base32, Base16. The current standard.
- RFC 7519 — JWT, which mandates Base64 URL for all three segments.
- RFC 7636 — PKCE, also Base64 URL.
FAQ
Why does my Base64 string fail to decode?
Most often: it's actually Base64 URL (uses - and _ instead of + and /), or padding (= characters at the end) is missing, or the string was HTML-escaped somewhere along the way (+ became a space). Try the Base64 URL tab.
Are Base64 and Base64 URL the same length?
Same encoded length before padding is stripped. Standard Base64 always pads to a multiple of 4 with = characters. Base64 URL strips padding, so an unpadded Base64 URL string can be up to two characters shorter than the equivalent standard Base64.
Can I just use Base64 in URLs?
Technically you can, but the + / and = characters all have meaning in URLs (+ is sometimes parsed as a space, / is a path separator, = is a query-string separator). Browsers and servers may rewrite them. Base64 URL exists specifically to dodge this.
How do I decode a JWT?
A JWT is three Base64 URL-encoded segments separated by dots: header.payload.signature. Split on dots, decode the first two segments as Base64 URL, parse each as JSON. The signature is binary; you don't read it directly, you verify it against the header+payload using the algorithm in the header.
Is Base64 encryption?
No. Base64 is a reversible encoding — anyone can decode it without a key. Use it for transport (binary in text channels) and identifier-shape (URL-safe IDs), never for keeping secrets.