›The Shack ›Security ›What Is URL-Safe Base64?

What Is URL-Safe Base64 and When Should You Use It?

Back to All Posts

If you've worked with JWTs, OAuth tokens, or any system that passes encoded data through a URL, you've almost certainly encountered URL-safe Base64 — even if you didn't know it by name. It solves a specific, practical problem: standard Base64 uses two characters that have special meaning in URLs, so encoded data placed in a query string or path can break routing, get misinterpreted, or simply fail to round-trip correctly. URL-safe Base64 is a minor variant of the standard that eliminates this problem with two small substitutions.

The URL-Safe Base64 encoder/decoder on DevToolShack handles both variants in your browser. Here is what to know about when to use which one.

A Quick Recap of Standard Base64

Base64 encodes binary data as printable ASCII text by converting every three bytes of input into four characters drawn from a 64-character alphabet. That alphabet is: A–Z, a–z, 0–9, +, and /. Padding characters (=) are added to the end to make the output length a multiple of four.

The full mechanics and use cases for standard Base64 are covered in the post on Base64 encoding explained. The short version: it's not encryption, just a way to represent binary data as text so it can travel through systems that only handle ASCII.

Why Standard Base64 Breaks in URLs

Two characters in the standard Base64 alphabet have reserved meanings in URLs:

  • + is interpreted as a space character in query strings (a legacy encoding from HTML form submissions).
  • / is a path separator, so it can split what should be a single token across multiple path segments.

The padding character = also causes problems in some contexts. It is used as a delimiter in query strings (key=value), and while percent-encoding it as %3D technically works, it adds noise and some systems strip it.

Consider a Base64-encoded value like ab+cd/ef== placed in a URL:

https://example.com/token/ab+cd/ef==

/* The server sees: */
path: /token/ab cd   (+ decoded as space in some frameworks)
path: /token/ab+cd   (/ splits the path at "ef")
/* Neither is the token you encoded. */

Percent-encoding the characters is one workaround, but it makes the value longer and depends on every intermediary in the chain correctly preserving the encoding — which isn't always guaranteed.

The URL-Safe Base64 Alphabet

URL-safe Base64 (defined in RFC 4648, Section 5) makes two substitutions to the standard alphabet:

  • + is replaced with - (hyphen)
  • / is replaced with _ (underscore)

Both - and _ are safe in URLs without percent-encoding. Everything else in the encoding process remains identical. The same input produces the same output, just with those two characters swapped wherever they appear.

Padding (=) is often omitted in URL-safe Base64 as well, since the length of the encoded string is deterministic and the padding isn't needed for decoding when the length is known. Many implementations drop it; others keep it. If you're decoding URL-safe Base64 from an external system and getting errors, missing padding is a common culprit.

Where You'll Encounter URL-Safe Base64

JWTs (JSON Web Tokens) use URL-safe Base64 for all three of their components: the header, the payload, and the signature. Because JWTs are often passed as URL parameters, Bearer tokens in Authorization headers, or stored in cookies, they need an encoding that survives all of those contexts. The JWT Decoder on DevToolShack decodes all three parts of any JWT you paste in, which makes it easy to inspect the encoded claims.

OAuth 2.0 and PKCE use URL-safe Base64 for the code verifier and code challenge values passed in authorization URLs.

Data URIs in CSS and HTML sometimes use URL-safe Base64 when the data URI is embedded in a URL context, though standard Base64 is more common for inline data URIs.

File identifiers and tokens in APIs that include encoded IDs in URL paths use URL-safe Base64 to avoid path parsing issues.

Encoding and Decoding in Code

JavaScript's built-in btoa() and atob() functions use standard Base64, not URL-safe. To produce URL-safe output you need to post-process:

// Encode to URL-safe Base64
function toUrlSafeBase64(str) {
  return btoa(str)
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');  // strip padding
}

// Decode from URL-safe Base64
function fromUrlSafeBase64(str) {
  // Re-add padding if needed
  str = str.replace(/-/g, '+').replace(/_/g, '/');
  while (str.length % 4) str += '=';
  return atob(str);
}

In Python, the base64 module has dedicated functions: base64.urlsafe_b64encode() and base64.urlsafe_b64decode(). They handle the character substitution automatically, though urlsafe_b64decode() requires padding to be present or it raises an error — so you may need to add it back before decoding.

import base64

# Encode
encoded = base64.urlsafe_b64encode(b'hello world').decode()
# → 'aGVsbG8gd29ybGQ='

# Decode (add padding if needed)
data = base64.urlsafe_b64decode(encoded + '==')

Choosing the Right Variant

The decision is straightforward. Use URL-safe Base64 when your encoded data will appear in a URL, a JWT, an OAuth flow, a cookie value, or any other context where + and / could be misinterpreted. Use standard Base64 for everything else: email attachments, MIME encoding, data URIs in HTML, HTTP Basic Auth headers, and file content.

When in doubt, check the spec. If you're implementing a protocol or integrating with an API that specifies Base64 encoding, the documentation will tell you which variant to use. RFC 4648 defines both: Section 4 for standard Base64 and Section 5 for the URL-safe variant.

For quick encoding and decoding of either variant without writing any code, the URL-Safe Base64 tool and the standard Base64 encoder/decoder are both available on DevToolShack. If you also need to URL-encode data for query strings, that's a separate operation covered by percent-encoding — not Base64 — and the URL Encoder/Decoder handles that.