Base64 を Base64URL に変換する方法
- 入力 · Base64 に Base64 を貼り付けます。折り返された Base64 の改行や
data:...;base64,接頭辞は自動で取り除かれます。 - 出力 · Base64URL に URLセーフな文字列が表示されます。
- 受け取る側が末尾の
=を必要とする場合は、出力の下の パディング(=) にチェックを入れます。 - 出力をコピー します。Base64URL → Base64 の切り替えか、Base64URL を Base64 に変換 で元に戻せます。
入力はいったんバイト列にデコードしてから再エンコードするので、有効な Base64 でない文字列は中途半端に変換されず、エラーになります。
例
| Base64 | Base64URL | 備考 |
|---|---|---|
PDw/Pz8+Pg== | PDw_Pz8-Pg | / と + を置換、== を削除 |
eyJyb2xlIjoiYWRtaW4+In0= | eyJyb2xlIjoiYWRtaW4-In0 | > を含む JSON、= を 1 つ削除 |
E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw+cM= | E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM | RFC 7636 付録 B の PKCE チャレンジ |
+/8= | -_8 | バイト列 fb ff |
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 | 変化なし:+、/、= を含まない |
最後の行のケースはよくあります。短い JSON や ASCII テキストは + や / を含まずにエンコードされることが多く、長さが 3 バイトの倍数ならパディングも付かないので、2 つの形式はまったく同じになります。そのため変換を忘れていてもテストでは気づかず、たまたま + や / が出る値になって初めて問題が表面化することがあります。
URL を壊す標準 Base64 の文字
標準の Base64 のうち 3 つの文字は、URL の中で特別な意味を持ちます。
+はクエリ文字列では空白を意味するので、多くのフレームワークで?t=a+bはa bとして届きます。/はパスの区切りなので、パスに入れた Base64 が分割されたり、誤ってルーティングされたりします。=はクエリパラメータの名前と値を区切るため、安全に使うには%3Dと書く必要があります。
こうした場合のために RFC 4648 の 5 章が定めているのが Base64URL で、+ と / の代わりに - と _ を使い、パディングは省略してもかまいません。このような値は、パス、クエリ文字列、Cookie、ファイル名にエスケープなしで入れられます。詳しくは Base64 と Base64URL の違い の記事で解説しています。
Base64URL が必須となる場面
- JWT と JWS。 JSON Web Token の 3 つのセグメントはすべて、パディングなしの Base64URL を使います。JWT デコーダー で読むことができ、形式については JWT での Base64 で説明しています。
- OAuth の PKCE。 ハッシュツールは verifier の SHA-256 ダイジェストを標準の Base64 で出力することが多い一方、
code_challengeはそのダイジェストをパディングなしの Base64URL にしたものでなければなりません。この変換が最後の手順です。 - WebAuthn と JWK。 クレデンシャル ID、チャレンジ、JSON Web Key の鍵パラメータは Base64URL です。
- 署名付き URL やリンク内のトークン。 パスワードリセットやダウンロードのリンクなど、値がパスやクエリ文字列に入る場合です。
標準形式を経由せずにテキストを直接 Base64URL にエンコードするには、Base64URL エンコーダー を使ってください。
コードで Base64 を Base64URL に変換する
import base64
base64.urlsafe_b64encode(b"<<???>>").rstrip(b"=").decode() # 'PDw_Pz8-Pg'
Buffer.from("PDw/Pz8+Pg==", "base64").toString("base64url"); // 'PDw_Pz8-Pg'
"PDw/Pz8+Pg==".replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); // same, without Buffer
Python の urlsafe_b64encode はパディングを残すので、rstrip で削っています。Node の "base64url" エンコーディングは最初から付けません。詳しくは Python と Node.js のガイドを参照してください。
よくある質問
Base64URL に変換するとデータは変わりますか?
変わりません。どちらのアルファベットも同じバイト列を表していて、違うのは 2 文字とパディングだけです。どちらの形式をデコードしても同じバイト列になります。
変換するときに = パディングは削除しますか?
受け取る側に合わせてください。JWT(RFC 7515)と PKCE(RFC 7636)ではパディングなしが必須です。両方を受け付けるライブラリもあれば、パディングを必須とする古いデコーダーもわずかにあり、その場合は パディング(=) にチェックを入れます。
正規表現で Base64 を Base64URL に変換できますか?
できます。JavaScript なら s.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "") です。入力が改行のない 1 行であることを前提にしているので、PEM ファイルやメールから取ったものは先に改行を取り除いてください。
標準の Base64 をパーセントエンコードする方法もありますか?
動きはしますが、+、/、= がそれぞれ 3 文字の %2B、%2F、%3D になります。しかも、URL を二重にデコードしたり + を空白として読んだりするシステムでは、値がやはり壊れます。Base64URL にはどちらの問題もありません。