Web Development

Base64URL and Other Base64 Variants Explained

Understand the differences between standard Base64, Base64URL, and other variants defined in RFC 4648, and learn when to use each format for your specific use case.

By Inventive HQ Team

Base64URL is standard Base64 with exactly two character swaps and one behavior change: the 62nd alphabet character + becomes -, the 63rd character / becomes _, and the trailing = padding is usually dropped. Those three characters — +, /, and = — are precisely the ones that break when Base64 data lands in a URL, a query string, or a filename, so RFC 4648 Section 5 defines a URL-safe variant that eliminates them. The decoded bytes are byte-for-byte identical to standard Base64; only two letters of the alphabet and the padding differ. This is why JSON Web Tokens, OAuth codes, and WebAuthn challenges all use Base64URL rather than plain Base64.

That's the summary an AI Overview will hand you. What it can't show you is the transformation happening character by character, why a real encoded value contains the exact bytes that force the swap, and how the six common variants stack up when you actually have to choose one. The animated diagram below walks a single value from standard Base64 to Base64URL, and the comparison table further down is the decision guide the summary flattens into a sentence.

Standard Base64 transforming into URL-safe Base64URL The value +vv8/f4= is shown in standard Base64. The plus becomes a hyphen, the slash becomes an underscore, and the equals padding is removed, producing the Base64URL value -vv8_f4. Base64 → Base64URL: three changes Encoding the raw bytes FA FB FC FD FE

Standard +vv8/f4=

swap 62nd & 63rd chars, drop padding

Base64URL -vv8_f4

URL-unsafe: + / = URL-safe: - _ (no padding)
Base64URL changes only the two alphabet characters that collide with URL syntax, then drops padding.

In this guide we'll walk the Base64 variants defined in RFC 4648, explain the exact technical differences, examine where each shows up in production, and give you a decision table for choosing correctly.

The Problem Standard Base64 Solves (and Creates)

Standard Base64 encoding uses 64 characters to represent binary data as text:

  • A-Z (26 uppercase letters)
  • a-z (26 lowercase letters)
  • 0-9 (10 digits)
  • + (plus sign)
  • / (forward slash)
  • = (padding character)

While this works perfectly for many applications, the special characters +, /, and = create problems in specific contexts:

URL and Query Parameter Issues

URLs have special meanings for certain characters:

  • / denotes path separators in URLs
  • + is interpreted as a space in query parameters
  • = is used for query parameter key-value assignment

When standard Base64-encoded data appears in URLs, these characters cause ambiguity and require additional percent-encoding, making URLs longer and harder to read.

Filename Compatibility Problems

On various operating systems:

  • / is a path separator (Linux, macOS, Windows)
  • Some filesystems restrict special characters
  • Filenames with + or / can cause shell scripting issues

Legacy System Incompatibility

Older text processing tools and indexing systems treat / and + as word breaks, causing issues with:

  • Full-text search systems
  • Text indexers
  • Legacy data processing pipelines

These problems led to the development of Base64URL, a URL-safe variant that eliminates special character issues.

Try it in your browser below — everything runs client-side:

Loading interactive tool...

Base64URL: The URL-Safe Variant

Base64URL, formally specified in RFC 4648 Section 5, modifies standard Base64 to be completely safe for URLs and filenames.

Key Differences from Standard Base64

Base64URL makes exactly three changes to the standard Base64 alphabet:

Character Substitutions:

  • Replaces + with - (hyphen/minus)
  • Replaces / with _ (underscore)

Padding Handling:

  • Padding characters (=) are typically omitted
  • When padding is used, it may be percent-encoded in URLs as %3D

The Complete Base64URL Character Set

A-Z (uppercase): A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a-z (lowercase): a b c d e f g h i j k l m n o p q r s t u v w x y z
0-9 (digits):    0 1 2 3 4 5 6 7 8 9
62nd character:  - (hyphen, instead of +)
63rd character:  _ (underscore, instead of /)

Encoding Example Comparison

Let's encode the same data with both variants. To make the difference visible we need bytes that actually produce + and / — plain ASCII text often doesn't. Here we encode the five raw bytes FA FB FC FD FE (a value you might see in a binary key or hash fragment):

Standard Base64:

+vv8/f4=

Base64URL (unpadded):

-vv8_f4

Notice how:

  • + became -
  • / became _
  • Padding = was removed (though Base64URL may optionally include it)

You can reproduce this exactly: python3 -c "import base64; print(base64.b64encode(bytes([0xfa,0xfb,0xfc,0xfd,0xfe])).decode())" prints the standard form, and base64.urlsafe_b64encode(...) prints -vv8_f4= (drop the = for the unpadded form).

Padding in Base64URL

Standard Base64 always includes padding (= characters) to make the encoded output length a multiple of 4. Base64URL handles padding differently:

No padding (common in URLs):

-vv8_f4

With padding (less common):

-vv8_f4=

Why omit padding?

  • The = character is percent-encoded as %3D in URLs, adding overhead
  • Decoders can infer padding from the data length
  • Shorter URLs are more user-friendly

Most Base64URL implementations omit padding by default but can decode both padded and unpadded variants.

Real-World Applications of Base64URL

Base64URL isn't just a theoretical variant—it's widely used in modern web technologies.

JSON Web Tokens (JWT)

JWTs are perhaps the most prominent use of Base64URL. A JWT consists of three Base64URL-encoded parts separated by periods:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Each part is Base64URL-encoded:

  1. Header: Algorithm and token type
  2. Payload: Claims (user data, expiration, etc.)
  3. Signature: Cryptographic signature for verification

JWTs use Base64URL because tokens are transmitted in:

  • HTTP headers (Authorization: Bearer )
  • URL query parameters (?token=)
  • Cookies (where special characters cause issues)

OAuth 2.0 and OpenID Connect

OAuth 2.0 tokens, authorization codes, and state parameters use Base64URL encoding to ensure compatibility across diverse URL structures and redirect mechanisms.

URL Shorteners and Identifiers

Services that generate short, unique identifiers often use Base64URL:

  • YouTube video IDs: dQw4w9WgXcQ
  • URL shorteners: bit.ly/2XyZ3aB
  • Database record identifiers in REST APIs: /api/users/Ab12Cd-3_eF

These identifiers are URL-safe by design, working seamlessly in paths and query parameters.

Advertisement

Web Crypto API

Browser-based cryptography (Web Crypto API) uses Base64URL for keys, signatures, and encrypted data that may appear in URLs or be stored in web-friendly formats.

FIDO2/WebAuthn

Modern passwordless authentication standards (FIDO2, WebAuthn) transmit challenge-response data using Base64URL encoding for browser-server communication.

Other Base64 Variants

While Base64URL is the most important variant, RFC 4648 and other standards define additional encoding schemes.

Standard Base64 (RFC 4648 Section 4)

The original Base64 encoding using +, /, and = padding. Used when URL safety isn't required:

  • Email attachments (MIME)
  • PEM certificates
  • Data URLs in HTML/CSS
  • Binary data in JSON (non-URL contexts)

Base64 Without Padding

Some implementations use standard Base64 but omit padding characters:

With padding (standard):

SGVsbG8=

Without padding:

SGVsbG8

Decoders calculate required padding automatically, making it optional in non-strict contexts.

MIME Base64 (RFC 2045)

MIME Base64, used for email attachments, adds line breaks every 76 characters for compatibility with legacy email systems:

SGVsbG8sIFRoaXMgaXMgYSBsb25nIG1lc3NhZ2UgdGhhdCBleGNlZWRzIDc2IGNoYXJhY3RlcnMg
YW5kIHRoZXJlZm9yZSBnZXRzIHdyYXBwZWQgdG8gbXVsdGlwbGUgbGluZXMgZm9yIE1JTUUgY29t
cGF0aWJpbGl0eQ==

Modern email systems handle longer lines, but MIME Base64 maintains backward compatibility.

Base32 and Base16 (Hex)

RFC 4648 also defines Base32 and Base16 (hexadecimal) encoding schemes:

Base32:

  • Uses 32 characters: A-Z and 2-7
  • Less efficient (20% overhead vs. Base64's 33%)
  • More human-friendly (case-insensitive)
  • Used in TOTP authentication codes, some backup codes

Base16 (Hex):

  • Uses 16 characters: 0-9 and A-F
  • 100% size overhead (doubles data size)
  • Extremely simple and universally compatible
  • Used for hash outputs, color codes, low-level debugging

UTF-7 (Obsolete)

UTF-7 was an email encoding scheme that used a modified Base64 alphabet. It's now obsolete and should not be used due to security vulnerabilities.

Base64 Variants at a Glance

VariantAlphabet (62nd / 63rd)PaddingSize overheadWhere it's used
Standard Base64 (RFC 4648 §4)+ / /Always =~33%MIME email, PEM certs, data: URLs, JSON blobs
Base64URL (RFC 4648 §5)- / _Usually omitted~33%JWT/JWS, OAuth 2.0, WebAuthn/FIDO2, URL-safe IDs
Base64 no-padding+ / /None~33%Compact standard-alphabet contexts
MIME Base64 (RFC 2045)+ / /Always =~33% + line breaksSMTP attachments, legacy mail (76-char lines)
Base32 (RFC 4648 §6)A-Z, 2-7= (often dropped)~60%TOTP secrets, backup codes, human-typed strings
Base16 / Hex (RFC 4648 §8)0-9, A-FNone100%Hash digests, color codes, low-level debugging
Which should I use?URL/token/filename → Base64URL. Email/cert/data-URL → Standard Base64. Human-typed codes → Base32. Hash display → Hex.

Use the detailed decision guide below to confirm the choice for your exact scenario.

Choosing the Right Base64 Variant

Use this decision guide to select the appropriate encoding variant:

Use Standard Base64 When:

  • Encoding email attachments
  • Generating PEM certificates
  • Creating data URLs for HTML/CSS
  • Working with APIs that explicitly require standard Base64
  • URL safety isn't a concern

Use Base64URL When:

  • Encoding data for URLs or query parameters
  • Generating tokens (JWT, OAuth2)
  • Creating URL-safe identifiers
  • Building filename-safe strings
  • Working with web authentication (WebAuthn, FIDO2)

Use MIME Base64 When:

  • Creating email attachments
  • Ensuring compatibility with legacy email systems
  • Working with SMTP-based systems

Use Base32 When:

  • Generating human-readable codes (case-insensitive)
  • Creating TOTP tokens
  • Building systems where humans must type codes

Use Hexadecimal (Base16) When:

  • Displaying hash outputs (SHA-256, MD5)
  • Low-level binary debugging
  • Working with color codes
  • Maximum compatibility is required

Technical Implementation Considerations

When implementing or using Base64 variants, consider these technical details:

Alphabet Consistency

Ensure your encoder and decoder use the same alphabet. Mixing standard Base64 encoding with Base64URL decoding produces garbage:

// WRONG: Encoding mismatch
const standardEncoded = btoa("data");  // Standard Base64
const urlDecoded = base64url.decode(standardEncoded);  // Fails if data contains + or /

// CORRECT: Matching variants
const urlEncoded = base64url.encode("data");
const urlDecoded = base64url.decode(urlEncoded);

Padding Tolerance

Good decoders should handle both padded and unpadded input:

// Both should decode successfully
"SGVsbG8="   // Padded
"SGVsbG8"    // Unpadded

Character Validation

When accepting Base64-encoded input, validate character sets to prevent injection attacks or errors:

Standard Base64: Only A-Z, a-z, 0-9, +, /, = Base64URL: Only A-Z, a-z, 0-9, -, _, =

Library Support

Most modern programming languages provide built-in support for multiple Base64 variants:

JavaScript (Node.js):

// Standard Base64
const standard = Buffer.from('data').toString('base64');

// Base64URL
const urlSafe = Buffer.from('data').toString('base64url');

Python:

import base64

# Standard Base64
standard = base64.b64encode(b'data')

# Base64URL
url_safe = base64.urlsafe_b64encode(b'data')

Java:

import java.util.Base64;

// Standard Base64
String standard = Base64.getEncoder().encodeToString("data".getBytes());

// Base64URL
String urlSafe = Base64.getUrlEncoder().encodeToString("data".getBytes());

Converting Between Variants

Converting between standard Base64 and Base64URL is straightforward—simply replace the special characters:

Base64 to Base64URL:

function base64ToBase64Url(base64) {
  return base64
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=/g, '');  // Remove padding
}

Base64URL to Base64:

function base64UrlToBase64(base64url) {
  let base64 = base64url
    .replace(/-/g, '+')
    .replace(/_/g, '/');

  // Add padding
  while (base64.length % 4) {
    base64 += '=';
  }

  return base64;
}

Security Considerations

While Base64 variants don't provide security (they're encoding, not encryption), choosing the right variant prevents security-related bugs:

URL Injection Prevention

Base64URL prevents URL parsing issues that could lead to injection vulnerabilities. Standard Base64 in URLs might be misinterpreted, potentially causing security issues.

Filename Traversal Prevention

Using Base64URL for filenames prevents path traversal attacks since / is replaced with _.

Consistent Encoding

Always use the same variant throughout your application to prevent decoding errors that could cause security issues (failed authentication, incorrect authorization, etc.).

Best Practices

Follow these best practices when working with Base64 variants:

  1. Use Base64URL for URLs: Always use Base64URL when encoded data appears in URLs, query parameters, or paths
  2. Document your choice: Clearly document which variant you're using in API documentation
  3. Be consistent: Use the same variant throughout an application or system
  4. Handle both padding styles: Build decoders that accept padded and unpadded input
  5. Validate input: Check that input uses expected characters before decoding
  6. Use standard libraries: Leverage built-in Base64 functions rather than implementing your own
  7. Test edge cases: Verify encoding/decoding with data containing characters near alphabet boundaries

Conclusion

Base64 variants exist to solve specific compatibility challenges. Standard Base64 works perfectly for email attachments and data URLs, but its special characters (+, /, =) cause problems in URLs and filenames. Base64URL solves these issues by replacing problematic characters with URL-safe alternatives (-, _), making it the preferred choice for web tokens, API identifiers, and URL-embedded data.

Understanding these variants and when to use them prevents bugs, improves compatibility, and ensures your encoded data works seamlessly across different systems and contexts. The key is matching the variant to your use case—standard Base64 for general encoding, Base64URL for web-facing applications, and specialized variants like Base32 or MIME Base64 for their specific scenarios.

Ready to work with different Base64 variants? Try our Base64 Encoder/Decoder tool with support for standard Base64, Base64URL, hexadecimal, and binary output formats.

Frequently Asked Questions

What is the difference between Base64 and Base64URL?

Base64URL (RFC 4648 Section 5) uses the same 64-value alphabet as standard Base64 with two substitutions: the 62nd character + becomes - and the 63rd character / becomes _. Padding = is also usually dropped. Those three characters (+, /, =) are exactly the ones that break inside URLs, query strings, and filenames, which is why Base64URL exists. The decoded bytes are identical either way — only the two alphabet characters and padding differ.

Why does JWT use Base64URL instead of standard Base64?

JWTs are transmitted in HTTP Authorization headers, URL query parameters, and cookies, where +, /, and = require percent-encoding and can be misparsed. Base64URL replaces +// with -/_ and omits padding so a token can be dropped into a URL or header verbatim without escaping. RFC 7515 (JWS) mandates unpadded Base64URL for all three JWT segments.

Does Base64URL use padding?

Usually not. Base64URL implementations typically omit the = padding because = percent-encodes to %3D in URLs and the decoder can infer the correct length from the number of remaining characters. Standards like JWS (RFC 7515) forbid padding entirely, while general RFC 4648 Base64URL allows it. Well-written decoders accept both padded and unpadded input.

What are the 62nd and 63rd characters in Base64URL?

In Base64URL the 62nd character (index 62) is - (hyphen-minus) and the 63rd (index 63) is _ (underscore). In standard Base64 those same two positions are + and /. Every other character (A-Z, a-z, 0-9) is identical across both alphabets.

Can I decode Base64URL data with a standard Base64 decoder?

Not reliably. A standard decoder does not recognize - or _ and will error or produce garbage when the data contains them. To convert, replace - with + and _ with /, then re-add = padding until the length is a multiple of 4. After that a standard Base64 decoder works.

Is Base64URL more secure than Base64?

No. Both are encodings, not encryption — anyone can reverse them. Base64URL is not more confidential. It does, however, prevent a class of bugs and injection issues that arise when raw +, /, or = land in URLs or filenames (path-separator confusion, query-parameter splitting), so it is safer to handle in those specific contexts.

How do I convert Base64 to Base64URL in JavaScript?

Chain three replacements on the standard string: .replace(/\+/g, '-'), .replace(/\//g, '_'), and .replace(/=+$/, '') to strip trailing padding. In Node.js you can skip the manual step entirely with Buffer.from(data).toString('base64url'), which emits unpadded Base64URL directly.

What character set does Base64URL allow?

Only A-Z, a-z, 0-9, -, and _, plus optional trailing = padding. Validating input against exactly this set before decoding rejects malformed or hostile data. Standard Base64, by contrast, permits + and / instead of - and _.

base64base64urlencodingRFC 4648URL encodingJWT