Base64 URL-safe
URLセーフなBase64(Base64url)のエンコード・デコード
プレーンテキスト
Base64
Base64urlエンコードとは?
Base64urlは、URL・ファイル名・その他のコンテキストで標準Base64の文字+と/が問題を引き起こす場面に特化して設計されたBase64エンコードの変種です。RFC 4648 Section 5で定義されており、Base64urlは+を-(ハイフン)に、/を_(アンダースコア)に置き換え、末尾の=パディング文字を省略します。その結果として得られる文字列は、追加のパーセントエンコードを必要とせず、URLクエリパラメータ・ファイル名・HTTPヘッダーに直接埋め込むことができます。
標準Base64(RFC 4648 Section 4)はA–Z・a–z・0–9・+・/の64文字を使用します。+と/はURLで予約されています。+はクエリ文字列(application/x-www-form-urlencoded)でスペースとして解釈され、/はパス区切り文字です。そのため標準Base64をURL内で使用するにはこれらの文字をパーセントエンコード(%2B・%2F)する必要があり、文字列が長くなり読みにくくなります。Base64urlは最初からURLセーフな文字を使用することでこの問題を完全に解消します。
Base64urlの最も代表的な用途はJSON Web Token(JWT)です。JWTの3つのセグメント——ヘッダー・ペイロード・署名——はすべてBase64urlでエンコードされています。OAuth 2.0のPKCEコード検証値・WebAuthnチャレンジ値・多くのAPIトークン方式もBase64urlに依存しています。このエンコードを理解することは、認証・認可・暗号データ交換を扱う開発者にとって不可欠です。
このBase64urlツールを使う理由
Base64urlとテキストまたはバイナリデータの相互変換をブラウザ上で直接行えます。エンコードとデコードの両方に対応し、パディングと文字置換を自動処理します。JWTトークンのデバッグ、PKCEコードチャレンジの生成、URLセーフな識別子の作成など、あらゆる場面でブラウザ内でローカルに処理が完結するため、遅延ゼロかつサーバーへの通信も不要です。
Base64urlのユースケース
標準Base64 vs Base64url
Base64urlと標準Base64の違いはちょうど3点です。エンコードアルゴリズムは同一——変わるのはアルファベットとパディングの扱いだけです:
| 特徴 | 標準(RFC 4648 §4) | Base64url(RFC 4648 §5) |
|---|---|---|
| Index 62 | + | - |
| Index 63 | / | _ |
| Padding | = (required) | Omitted |
この3つの違いにより、標準Base64とBase64urlの相互変換は簡単です:+を-に、/を_に置き換え、末尾の=を除去します。逆方向は-を+に、_を/に置き換え、長さが4の倍数になるようパディングを追加します。ほとんどの言語がネイティブのBase64urlサポートを提供しているため、手動変換は不要です。どちらの変換も完全に可逆かつロスレスであり、元のバイト列を正確に保持します。
エンコード比較表
以下の表は同じ入力を標準Base64とBase64urlでエンコードした結果を示しています。URLセーフ版ではパディング文字(=)が除去され、+と/が-と_に置き換えられていることを確認できます:
| 入力 | 標準Base64 | Base64url(パディングなし) |
|---|---|---|
| Hello | SGVsbG8= | SGVsbG8 |
| A | QQ== | |
| 1+1=2 | MSsxPTI= | MSsxPTI |
| subject?ref=1 | c3ViamVjdD9yZWY9MQ== | c3ViamVjdD9yZWY9MQ |
| ð (thumbs up) | 8J+RjQ== | 8J-RjQ |
コード例
主要な言語でBase64url文字列をエンコード・デコードする方法です。各例はURL・ファイル名・HTTPヘッダーで安全に使用できる出力を生成します:
// Encode to Base64url
function toBase64url(str) {
return btoa(unescape(encodeURIComponent(str)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
}
toBase64url('Hello!') // → "SGVsbG8h"
// Decode from Base64url
function fromBase64url(b64url) {
const b64 = b64url.replace(/-/g, '+').replace(/_/g, '/')
const pad = (4 - b64.length % 4) % 4
return decodeURIComponent(escape(atob(b64 + '='.repeat(pad))))
}
fromBase64url('SGVsbG8h') // → "Hello!"// Native base64url support since Node 15.7
const encoded = Buffer.from('Hello!').toString('base64url')
// → "SGVsbG8h"
const decoded = Buffer.from('SGVsbG8h', 'base64url').toString()
// → "Hello!"
// Decode a JWT payload
const jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0...'
const payload = JSON.parse(Buffer.from(jwt.split('.')[1], 'base64url').toString())
// → { sub: "1234567890" }import base64
# Encode to Base64url (no padding)
encoded = base64.urlsafe_b64encode(b'Hello!').rstrip(b'=').decode()
# → "SGVsbG8h"
# Decode from Base64url (re-add padding)
def b64url_decode(s: str) -> bytes:
s += '=' * (4 - len(s) % 4) # restore padding
return base64.urlsafe_b64decode(s)
b64url_decode('SGVsbG8h') # → b'Hello!'package main
import (
"encoding/base64"
"fmt"
)
func main() {
// Encode to Base64url (no padding)
encoded := base64.RawURLEncoding.EncodeToString([]byte("Hello!"))
fmt.Println(encoded) // → "SGVsbG8h"
// Decode from Base64url
decoded, _ := base64.RawURLEncoding.DecodeString("SGVsbG8h")
fmt.Println(string(decoded)) // → "Hello!"
}