Base64 vs Base64URL Encoding: What's the Difference?

Published March 9, 2026 · 6 min read

Base64 and Base64URL are two variants of the same encoding scheme, but they differ in two critical characters. This difference determines whether your encoded data can safely appear in URLs, filenames, and HTTP headers without breaking. If you work with API keys, JWTs, or any token that travels through URLs, understanding this distinction is essential.

The Core Difference

Both Base64 and Base64URL encode binary data into printable ASCII characters using a 64-character alphabet. They share 62 of those characters (A-Z, a-z, 0-9). The difference is the final two characters and the padding:

FeatureBase64 (RFC 4648 Sec. 4)Base64URL (RFC 4648 Sec. 5)
Character 62+- (hyphen)
Character 63/_ (underscore)
Padding= (required)Omitted (usually)

That is the entire difference. Base64URL replaces + with -, replaces / with _, and drops the trailing = padding characters.

Why Base64 Breaks in URLs

The three characters that Base64URL changes (+, /, =) all have special meaning in URLs:

If you include a standard Base64 string in a URL without percent-encoding it first, the URL parser will misinterpret these characters. Consider this example:

// Standard Base64 key
const key = "Abc+Def/Ghi=";

// Placed in a URL:
https://api.example.com/verify?key=Abc+Def/Ghi=

// The server receives:
// key = "Abc Def"  (+ became space, / split the path, = confused the parser)

You could percent-encode the Base64 string (Abc%2BDef%2FGhi%3D), but that defeats the purpose of using a compact encoding. Base64URL solves this by using URL-safe characters from the start.

// Base64URL key (same data)
const key = "Abc-Def_Ghi";

// Placed in a URL:
https://api.example.com/verify?key=Abc-Def_Ghi

// The server receives exactly: "Abc-Def_Ghi"

How to Convert Between Them

Base64 to Base64URL (JavaScript)

function base64ToBase64URL(base64) {
  return base64
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}

// Example
base64ToBase64URL("SGVsbG8gV29ybGQ=");
// Returns: "SGVsbG8gV29ybGQ"

Base64URL to Base64 (JavaScript)

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

  // Restore padding
  const pad = base64.length % 4;
  if (pad === 2) base64 += '==';
  else if (pad === 3) base64 += '=';

  return base64;
}

// Example
base64URLToBase64("SGVsbG8gV29ybGQ");
// Returns: "SGVsbG8gV29ybGQ="

Where Each Encoding Is Used

Base64 (standard) is used in:

Base64URL is used in:

Rule of thumb: if your encoded data will ever appear in a URL, filename, or cookie, use Base64URL. If it stays within structured formats like email or certificates, standard Base64 is fine.

JWTs Use Base64URL Exclusively

The JWT specification (RFC 7519) mandates Base64URL encoding without padding. This is not optional. If you implement JWT encoding or decoding manually, you must use the URL-safe alphabet.

// A JWT has three Base64URL-encoded parts separated by dots:
// header.payload.signature

const jwt = [
  btoa(JSON.stringify({alg:"HS256",typ:"JWT"}))
    .replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,''),
  btoa(JSON.stringify({sub:"1234567890",name:"John"}))
    .replace(/\+/g,'-').replace(/\//g,'_').replace(/=+$/,''),
  "signature_here"
].join('.');

// eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4ifQ.signature_here

Generating Base64URL Keys

Here is how to generate a cryptographically secure Base64URL-encoded API key in several languages:

JavaScript (Browser & Node.js)

function generateBase64URLKey(bytes = 32) {
  const buf = new Uint8Array(bytes);
  crypto.getRandomValues(buf);
  return btoa(String.fromCharCode(...buf))
    .replace(/\+/g, '-')
    .replace(/\//g, '_')
    .replace(/=+$/, '');
}
// 32 bytes = 43 characters = 256 bits entropy

Python

import secrets
import base64

def generate_base64url_key(byte_length=32):
    return base64.urlsafe_b64encode(
        secrets.token_bytes(byte_length)
    ).rstrip(b'=').decode('ascii')

Go

import (
    "crypto/rand"
    "encoding/base64"
)

func generateBase64URLKey(byteLength int) string {
    b := make([]byte, byteLength)
    rand.Read(b)
    return base64.RawURLEncoding.EncodeToString(b)
}

Note that Go's base64.RawURLEncoding uses Base64URL without padding by default. Python's urlsafe_b64encode includes padding, so you need to strip it manually.

Padding: To Include or Not?

Base64 padding (=) exists to signal that the encoded length is not a multiple of 4. It is needed for correct decoding in contexts where multiple Base64 strings are concatenated. In practice, most modern implementations can decode without padding by inferring the correct length.

The consensus in the API and token world is to omit padding. JWTs omit it. Most API key implementations omit it. Padding characters cause issues in URLs and add no value when keys are transmitted individually.

Summary

QuestionAnswer
Building an API key?Use Base64URL (no padding)
Working with JWTs?Use Base64URL (required by spec)
Encoding data for email/MIME?Use standard Base64
Encoding data for data: URIs?Use standard Base64
Need URL-safe encoding?Use Base64URL
Need to concatenate encoded strings?Use Base64 with padding

Generate Base64URL-encoded keys instantly with our free API key generator. Select "Base64URL" format and choose your preferred length.

Recommended Resources

For a deep dive into encoding, JWTs, and the Web Crypto API, JavaScript: The Definitive Guide covers Base64 handling and typed arrays thoroughly. For the cryptographic context of why encoding choices matter, Real-World Cryptography is the go-to reference.

SPUNK LLC Network

API Sites

Key Management

More from SPUNK LLC