JSON Web TokenにおけるBase64url
JWTがヘッダーとペイロードにBase64urlエンコードを使う仕組みを解説。JWTセグメントのデコード方法、パディングルール、よくあるJWTの誤りを紹介します。
Format
詳細な説明
JSON Web Token(JWT)は、ヘッダーとペイロードのセグメントに標準Base64ではなくBase64urlエンコードを使用します。このエンコードを理解することは、JWTベースの認証のデバッグ、検査、実装に不可欠です。
JWTの構造: JWTはドットで区切られた3つのパートで構成されます:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- ヘッダー(最初のセグメント):アルゴリズムとトークンタイプを指定するBase64urlエンコードされたJSON
- ペイロード(2番目のセグメント):クレーム(ユーザーデータ、有効期限など)を含むBase64urlエンコードされたJSON
- 署名(3番目のセグメント):ヘッダーとペイロードに対する暗号署名
なぜ標準Base64ではなくBase64urlなのか? JWTはURL内(クエリパラメータ、リダイレクトURI)やHTTPヘッダーに頻繁に含まれます。標準Base64の +、/、= 文字は、これらのコンテキストでパース上の問題を引き起こします。Base64urlはURLセーフな代替文字に置き換えることでこの問題を解決します。
JavaScriptでのJWTデコード:
function decodeJwtPayload(token) {
const payload = token.split(".")[1];
// Convert Base64url to Base64
const base64 = payload.replace(/-/g, "+").replace(/_/g, "/");
// Add padding
const padded = base64 + "=".repeat((4 - base64.length % 4) % 4);
// Decode
return JSON.parse(atob(padded));
}
重要なニュアンス:
- JWTのBase64urlセグメントにはパディング(
=)が含まれません。RFC 7515仕様では、パディングを省略しなければならないと明示されています。 - 署名セグメントもBase64urlエンコードされていますが、デコードすると生のバイト列(JSONではない)が得られます。検査のためにデコードするのはヘッダーとペイロードのセグメントのみです。
- JWTはデフォルトでは署名されているだけで、暗号化されていません。Base64urlエンコードは暗号化ではありません。誰でもJWTのペイロードをデコードして読むことができます。ペイロードに隠すべき機密データが含まれる場合はJWE(JSON Web Encryption)を使用してください。
よくある間違い:
- Base64urlから標準Base64に変換せずにJWTセグメントに対して直接
atob()を使用すること。文字化けした出力やエラーが発生します。 - デコードされたペイロードが常に有効なJSONであると仮定すること。不正に作成されたり改ざんされたトークンは、無効なJSONを生成する可能性があります。
- 署名を検証せずにJWTをデコードしてその内容を信頼すること。デコードは簡単ですが、検証がセキュリティの要です。
ユースケース
OAuth 2.0やOpenID Connectフローのデバッグのために、認証トークンのヘッダーとペイロードのクレームをデコードして表示するJWTインスペクターツールを構築する場合に使用します。