Base64URL vs Base64: when the extra characters matter
The + / = characters in standard Base64 break URLs, filenames, and JWT headers. Base64URL is the fix — and it's almost but not quite a drop-in replacement.
# The characters that cause trouble
Standard Base64 uses 64 characters: A–Z, a–z, 0–9, plus + and /, with = for padding.
Three of those cause problems in common places:
+in a URL query string means space. So?token=abc+defparses astoken=abc def, destroying your payload./is a path separator. A filename or URL component containing/breaks trivially.=is the query-string separator. Padding at the end of a Base64 token collides with URL syntax.
# The fix: Base64URL
Defined in RFC 4648 § 5. Two tiny changes:
+→-/→_- Padding (
=) is optional, often dropped entirely
Base64: SGVsbG8gV29ybGQ=
Base64URL: SGVsbG8gV29ybGQ
Same bytes decoded. Safe to drop into a URL without %-encoding, safe as a filename, safe as a JWT segment.
# Where you'll see it
- JWT — all three parts (header, payload, signature) are Base64URL.
- OAuth —
code_challenge,state, and PKCE values. - WebAuthn — credential IDs and public keys.
- Short-link generators — encoding numeric IDs as URL-safe text.
- Data URLs with a URL-encoded mode — less common, but permitted.
# Converting between them
<div class="callout callout-tip" role="note"><div class="callout-title">Tip</div><div class="callout-body"><p>If a library gives you Base64 but the destination wants Base64URL, you can convert in-place: replace <code>+</code> with <code>-</code>, <code>/</code> with <code>_</code>, and strip trailing <code>=</code>. Going back adds them in the same order.</p></div></div>
function toBase64Url(b64) {
return b64.replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
}
function fromBase64Url(b64url) {
const padded = b64url + "=".repeat((4 - b64url.length % 4) % 4);
return padded.replaceAll("-", "+").replaceAll("_", "/");
}
# Common bugs
- Using a library's Base64 encoder and dropping into a URL without converting first. The
+gets URL-encoded to%2Bby the client but the server decodes it back to space, not+. Silent data corruption. - Forgetting padding on decode. Many Base64URL producers omit
=; if your decoder is strict, it rejects the input. - Hand-rolling the conversion with a single
replace(which only replaces the first match) instead ofreplaceAllor a regex.
# In the browser
Our Base64 tool offers both modes via a toggle. Paste any Base64URL string, flip the switch, see the decoded bytes.
# Related tools
- Base64 Encode / Decode
- URL Encode / Decode
- JWT Decoder — tokens are three Base64URL segments
Frequently asked questions
›Can I decode a Base64URL string with a regular Base64 decoder?
Not directly — swap `-` back to `+` and `_` back to `/`, then pad with `=` to a multiple of 4 characters. Many decoders have a `urlSafe` option that does this automatically.
›Why does Base64URL drop padding?
The `=` character has special meaning in URL query strings (`key=value`). Dropping it keeps the Base64 payload usable in a URL parameter without escaping. Decoders know how much padding to infer from the length.