Base64 vs Base64URL

Base64URL is a URL-safe variant of standard Base64. It swaps the two problematic characters — + becomes - and / becomes _ — and usually drops the = padding, so the output is safe to drop into URLs, filenames, and JWTs without further escaping. The decoded bytes are identical.

What's the difference between Base64 and Base64URL?

Both encodings turn binary data into ASCII text using an alphabet of 64 characters, and 62 of those characters are exactly the same: A–Z, a–z, and 0–9. The entire difference lives in the last two alphabet slots — characters 62 and 63 — plus how padding is handled. Standard Base64 uses + and /; Base64URL uses - and _. That is the whole substitution.

Because only the surface characters change, the two variants are interchangeable representations of the same bytes. You can convert one to the other with a character swap and never touch the underlying data. The table below lays out every point of difference:

Aspect Standard Base64 Base64URL
Character 62 + (plus) - (hyphen)
Character 63 / (slash) _ (underscore)
Padding = required / typical = usually omitted
Safe in URLs? No Yes
Safe in filenames? No Yes
Defined by RFC 4648 §4 RFC 4648 §5
Typical uses MIME, email, data URIs JWT, URLs, filenames, tokens

Why does Base64URL exist?

Base64URL exists because standard Base64's alphabet collides with characters that have reserved meaning in URLs and file paths. Three characters cause trouble:

  • / — a path separator. Drop it into a URL and everything after it looks like a new path segment.
  • + — in application/x-www-form-urlencoded query strings, + decodes to a space, silently corrupting the value.
  • = — the key/value separator in query strings, so trailing padding can confuse parsers.

The workaround with standard Base64 is percent-encoding: + becomes %2B, / becomes %2F, and = becomes %3D. That works, but it makes tokens longer, harder to read, and easy to double-encode by mistake. A single Base64 string embedded raw in a URL can be corrupted the moment it passes through a form decoder or a router that treats / as a boundary.

Base64URL sidesteps the whole problem. By choosing - and _ — both of which are unreserved in URLs — and dropping padding, the encoded output can be pasted directly into a path segment, query parameter, cookie, or filename with zero escaping. There is nothing to percent-encode and nothing to break. For a broader tour of the URL-safe variant, see URL-Safe Base64 (RFC 4648).

When should I use Base64URL?

Reach for Base64URL whenever the encoded string will land somewhere that a URL, path, or token parser can see. The clearest examples:

  • JWTs: All three segments — header, payload, and signature — are Base64URL with no padding. This is mandated by the spec, not a convention. See Base64 in JWT.
  • Tokens in URLs and query parameters: Password-reset links, OAuth state and PKCE values, unsubscribe tokens, share links.
  • Filenames and object keys: Anywhere / would be read as a directory separator — S3 keys, content-addressed filenames.
  • Cache keys and cookies: Values that must avoid reserved punctuation.

Stick with standard Base64 when the target is not a URL: MIME and email attachments (RFC 2045), data URIs in CSS and HTML, PEM certificates, HTTP Basic Auth headers, and JSON binary fields where readability and tooling expect + and /. If you are unsure, ask one question: does this string ever travel through a URL or a filesystem path? If yes, use Base64URL; if no, standard Base64 is the safer default.

Do I need the padding?

Almost never in URL-safe contexts. Padding (=) exists so that the output length is always a multiple of 4, but that information is fully derivable from the string itself — the remainder of the length modulo 4 tells a decoder how many padding characters were dropped. Because it is redundant, RFC 4648 §5 explicitly allows omitting it in URL-safe settings, and the JWT specification mandates no padding at all.

Bytes  Base64 (padded)   Base64URL (unpadded)
─────────────────────────────────────────────
1      "TQ=="            "TQ"
2      "TWE="            "TWE"
3      "TWFu"            "TWFu"   (no padding needed)

The one thing to remember: many standard decoders insist on a length that is a multiple of 4 and will reject an unpadded string. So when decoding Base64URL, you re-add = until the length is a multiple of 4, then decode. The base64.dev decoder does this re-padding automatically, so you can paste an unpadded JWT segment and it just works. For the full story on why padding is optional and how it is computed, see Base64 padding.

How do I convert between Base64 and Base64URL?

Converting is a character swap, not a re-encode. You never decode and re-encode the bytes — you only translate the two differing characters and adjust padding. In JavaScript:

// standard -> url-safe
const urlSafe = std.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');

// url-safe -> standard (re-pad)
let s = url.replace(/-/g, '+').replace(/_/g, '/');
while (s.length % 4) s += '=';

Most languages ship the variant natively, so you rarely need the manual swap:

  • Python: base64.urlsafe_b64encode() / urlsafe_b64decode()
  • Node.js: Buffer.from(str, 'base64url') and buf.toString('base64url')
  • Go: base64.RawURLEncoding (unpadded) or base64.URLEncoding (padded)
  • Java: Base64.getUrlEncoder() / getUrlDecoder()

Or skip the code entirely: the live tool at base64.dev/base64url encodes and decodes Base64URL in your browser, and re-pads unpadded input for you.

Frequently Asked Questions

What's the difference between Base64 and Base64URL?

Base64URL is a URL-safe variant of standard Base64. It replaces + with - and / with _, and usually drops the = padding, so the output is safe in URLs, filenames, and JWTs. Standard Base64 (RFC 4648 §4) targets MIME, email, and data URIs; Base64URL is RFC 4648 §5. Both encode the same underlying bytes.

Is Base64URL the same data as Base64?

Yes. They encode the exact same bytes — only two alphabet characters differ, plus optional padding. Convert the characters back and decode, and you get identical binary data. It is a display-level substitution, not a different encoding of the content.

Why do JWTs use Base64URL?

JWTs travel in URLs, HTTP headers, and cookies, where +, /, and = are unsafe or reserved. Base64URL avoids them, so a token needs no percent-encoding. The JWT spec (RFC 7519) requires Base64URL with no padding for the header, payload, and signature.

Does Base64URL have padding?

Usually not. RFC 4648 §5 permits it, but URL-safe contexts typically omit the trailing =, and JWT forbids it. Padding is redundant because it is derivable from the string length, so decoders re-add = until the length is a multiple of 4 before decoding.

How do I convert Base64URL back to standard Base64?

Replace - with + and _ with /, then re-pad with = until the length is a multiple of 4. No re-encoding of the bytes is needed. In JavaScript: s = url.replace(/-/g, '+').replace(/_/g, '/'); while (s.length % 4) s += '='; then atob(s).

Encode or decode Base64URL instantly

Paste any text or token into base64.dev/base64url to encode or decode URL-safe Base64 — no sign-up, runs in your browser.

Open Base64URL tool →