The journal
Base64 URL encoding explained
What Base64URL is, how it differs from URL percent-encoding, when to use it, and how to implement it safely with practical code and a deployment checklist.

Base64 URL encoding (Base64URL) is the URL- and filename-safe variant of Base64 that uses the same binary-to-text mechanism but swaps + and / for - and _ and often omits = padding so the result can be embedded in URLs without breaking parsing. The variant and its alphabet are defined in section 5 of RFC 4648, and the size expansion is still roughly one third compared with raw bytes, just like standard Base64 MDN.
What Base64URL is and why it exists
Base64 is a family of encodings that represent binary data as ASCII text. Base64URL keeps the Base64 mechanics but changes the alphabet so the output avoids characters that would require escaping in URLs or filenames: value 62 uses - and 63 uses _ (instead of + and /). RFC 4648 also notes that the padding character = is typically percent-encoded in URIs, and that if the data length is known implicitly, padding can be omitted RFC 4648.
Base64URL is not URL percent-encoding
Percent-encoding (often called URL encoding) escapes reserved characters inside an existing URL component. Base64URL is different: it re-encodes arbitrary bytes into a safe text alphabet. Use percent-encoding to escape a few characters in a value you already have; use Base64URL when you must transport raw bytes or opaque tokens as text in a URL. You generally do not apply both to the same bytes unless a specific protocol requires it. MDN distinguishes the URL-safe variant and notes you only need it when the data goes into a path segment or query parameter MDN.

How Base64URL differs from standard Base64
Alphabet and padding
- Alphabet change: 62 is - and 63 is _ (instead of + and /) RFC 4648.
- Padding: = is allowed but often omitted in URL contexts. RFC 4648 permits omitting padding when the length is known; if you do include = inside a URI it is typically percent-encoded RFC 4648.
- Size: Encoding still expands data by about 33% because Base64 maps each three bytes to four characters MDN.
Error handling and canonical bits
Base64 encoders must set the unused trailing bits in the final character(s) to zero; decoders may reject inputs where those bits are non-zero MDN. When interoperating with third-party code, decide whether you accept or require padding, and document that behavior.
When to use Base64URL vs percent-encoding
- Use Base64URL for small binary blobs or opaque tokens you need to place in a path or query parameter, or in filenames, where + and / would be problematic RFC 4648.
- Use percent-encoding to escape a handful of reserved characters inside a normal text parameter (for example, a space or ampersand inside a query value).
Because Base64 increases size by roughly one third, avoid putting large payloads in URLs; prefer references or body uploads instead MDN.

How to encode and decode Base64URL
JavaScript (browser)
The platform provides Base64 helpers. To get URL-safe output, replace characters and remove padding as defined by RFC 4648. Note that legacy btoa/atob operate on byte-like strings; for arbitrary Unicode text, follow MDN's guidance to convert via UTF-8 first MDN.
// Bytes to Base64URL
function toBase64Url(bytes) {
// bytes: Uint8Array
// In modern browsers you can also use Uint8Array.prototype.toBase64()
// then apply the replacements below; here we build from binary string
let bin = "";
for (const b of bytes) bin += String.fromCharCode(b);
const b64 = btoa(bin); // standard Base64
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
}
// Example
const bytes = new Uint8Array([0xde, 0xad, 0xbe, 0xef]);
console.log(toBase64Url(bytes)); // 3q2-7w
Python (standard library)
Python includes URL-safe helpers; if you want unpadded output, strip trailing =. Padding can be restored based on length modulo 4 when decoding. This mirrors the behavior described in RFC 4648 and is shown in Entrust's guidance Entrust nShield docs.
import base64
def b64url_encode(data: bytes, padded: bool = False) -> str:
s = base64.urlsafe_b64encode(data).decode('ascii')
return s if padded else s.rstrip('=')
def b64url_decode(s: str) -> bytes:
# restore padding to a multiple of 4
pad = '=' * ((4 - len(s) % 4) % 4)
return base64.urlsafe_b64decode(s + pad)
print(b64url_encode(b'hello', padded=False)) # aGVsbG8
print(b64url_decode('aGVsbG8')) # b'hello'
Common pitfalls
- Mixing mechanisms: Do not treat Base64URL as a substitute for percent-encoding. Percent-encoding escapes characters inside a URL component; Base64URL re-encodes bytes as safe text MDN.
- Padding mismatches: Some decoders require =, others accept both padded and unpadded forms. Pick a convention and normalize at boundaries RFC 4648.
- Thinking it's encryption: Base64 and Base64URL provide no confidentiality. RFC 4648 warns that base encodings do not add entropy and should not be used as a security control RFC 4648.
Ship Base64URL safely: preflight checklist
Related reading on Stack & Method
FAQ
Is Base64URL the same as standard Base64?
No. They share the same encoding mechanics, but Base64URL changes two characters in the alphabet (- and _ instead of + and /) and may omit = padding in URL contexts RFC 4648.
Do I need to percent-encode a Base64URL string?
Usually no, because Base64URL avoids reserved URL characters. The exception is the = padding character; if you include it in a URL, percent-encode it, or omit padding as allowed by RFC 4648 when the length can be inferred RFC 4648.