How to encode Base64URL
- Type or paste the text into Input · text.
- Copy the Base64URL from Output · Base64. URL-safe (- _) and No padding (=) are already ticked on this page.
- If the receiver wants padding, untick No padding (=). If it wants standard Base64, untick URL-safe as well, or use the Base64 encoder.
- Copy the output or download it as
base64.txt.
Decode a value with the Base64URL decoder. Base64 to Base64URL converts existing strings between the two alphabets.
What changes compared to standard Base64
Only three characters differ. Everything else, including the 3-bytes-to-4-characters rule, stays the same:
| Standard Base64 | Base64URL | |
|---|---|---|
| Value 62 | + | - |
| Value 63 | / | _ |
| Padding | = required | usually omitted |
| Defined in | RFC 4648, section 4 | RFC 4648, section 5 |
For many short strings the two variants differ only in padding. The alphabet difference appears whenever a 6-bit group has the value 62 or 63, which characters like ? and > and many non-ASCII bytes produce:
| Input | Standard | Base64URL, no padding |
|---|---|---|
Hi! | SGkh | SGkh |
?>?> | Pz4/Pg== | Pz4_Pg |
subjects?_d | c3ViamVjdHM/X2Q= | c3ViamVjdHM_X2Q |
https://example.com/?q=1 | aHR0cHM6Ly9leGFtcGxlLmNvbS8/cT0x | aHR0cHM6Ly9leGFtcGxlLmNvbS8_cT0x |
Base64 vs Base64URL covers the history and the decoding differences in more depth.
Why URLs need their own alphabet
Each of the three standard characters means something in a URL. / separates path segments, = separates names from values in a query string, and + is read as a space by form decoders. A standard Base64 value like a+b/c== in a query parameter arrives as a b/c== unless every character was escaped. Percent-encoding fixes that but turns each of them into three characters (%2B, %2F, %3D).
Base64URL picks two characters that are unreserved in URLs and drops the padding, so a value can be pasted into a path, a query string, a fragment, a cookie or a file name unchanged. - and _ are also safe in file names on every common file system, unlike /.
Where Base64URL is used
- JWT and JOSE. Every part of a JSON Web Token is Base64URL without padding, defined in RFC 7515. The JWT decoder reads tokens; Base64 in JWT explains the structure.
- OAuth PKCE. The
code_challengeis the Base64URL of the SHA-256 hash of thecode_verifier. - WebAuthn and passkeys. Credential IDs and challenges travel as Base64URL in JSON.
- Links and IDs. Share links, signed URL parameters and short IDs built from random bytes use it to stay URL-clean.
Base64URL in code
Node.js has a built-in base64url encoding, and Python a URL-safe function whose padding you strip yourself:
// Node.js
Buffer.from("subjects?_d").toString("base64url"); // "c3ViamVjdHM_X2Q"
// Browsers with Uint8Array.prototype.toBase64
new TextEncoder().encode("subjects?_d").toBase64({ alphabet: "base64url", omitPadding: true });
import base64, hashlib
base64.urlsafe_b64encode(b"subjects?_d").rstrip(b"=").decode() # 'c3ViamVjdHM_X2Q'
# PKCE code_challenge, example from RFC 7636 appendix B
verifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
digest = hashlib.sha256(verifier.encode("ascii")).digest()
base64.urlsafe_b64encode(digest).rstrip(b"=").decode()
# 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM'
More in Base64 in Node.js, JavaScript and Python, and the browser API in Uint8Array.toBase64.
FAQ
What is Base64URL?
The URL- and filename-safe variant of Base64 defined in RFC 4648, section 5. It uses - and _ as the last two alphabet characters instead of + and /, and is usually written without = padding.
Why not just percent-encode normal Base64?
It works but costs three characters for every +, / and =, and a missed escape turns + into a space when the query string is parsed. Base64URL avoids both problems.
Should I keep the = padding?
JWT and most URL-safe formats omit it, because = also needs escaping in URLs and the decoder can work out the padding from the length. Keep it only if the receiving system requires it: untick No padding.
How do I make a PKCE code_challenge?
Hash the code_verifier with SHA-256 and Base64URL-encode the 32 hash bytes without padding. This page encodes text, not hash bytes, so do it in code; the snippet below reproduces the RFC 7636 example.