PKCEコード検証子とチャレンジの生成
JavaScriptのWeb Crypto APIを使用して暗号学的に安全なPKCE code_verifierとcode_challengeを生成するステップバイステップガイド。
PKCE
詳細な説明
PKCEコード検証子とチャレンジの生成
PKCE拡張には2つの値が必要です:code_verifier(ランダムな秘密)とcode_challenge(検証子の派生ハッシュ)。検証子はクライアントが保持し、チャレンジは認可リクエスト時に認可サーバーに送信されます。
要件(RFC 7636)
| パラメータ | 要件 |
|---|---|
code_verifier |
[A-Z] [a-z] [0-9] - . _ ~から43-128文字 |
code_challenge |
メソッドがS256の場合、BASE64URL(SHA256(code_verifier)) |
code_challenge_method |
S256(推奨)またはplain(非推奨) |
JavaScript実装(Web Crypto API)
// ステップ1: ランダムなcode_verifierを生成
function generateCodeVerifier() {
const array = new Uint8Array(32);
crypto.getRandomValues(array);
return base64url(array);
}
// ステップ2: code_challengeを導出
async function generateCodeChallenge(verifier) {
const encoder = new TextEncoder();
const data = encoder.encode(verifier);
const digest = await crypto.subtle.digest("SHA-256", data);
return base64url(new Uint8Array(digest));
}
// ヘルパー: Base64URLエンコーディング(パディングなし)
function base64url(buffer) {
let str = "";
for (const byte of buffer) {
str += String.fromCharCode(byte);
}
return btoa(str)
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
}
// 使用方法
const verifier = generateCodeVerifier();
const challenge = await generateCodeChallenge(verifier);
console.log("code_verifier:", verifier);
console.log("code_challenge:", challenge);
Python実装
import os
import hashlib
import base64
code_verifier = base64.urlsafe_b64encode(os.urandom(32)).rstrip(b"=").decode()
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).rstrip(b"=").decode()
なぜPlainではなくS256か?
plainでは、code_challengeはcode_verifierと等しくなります。つまり、チャレンジ(フロントチャネルリダイレクトで送信)を傍受した攻撃者は即座に検証子を知ることができます。S256ではチャレンジはSHA-256ハッシュであり、攻撃者はそれを逆算して検証子を取得できません。常にS256を使用してください。
ユースケース
OAuth 2.0認可フローを開始する前に、JavaScript SPA、React Nativeモバイルアプリ、またはNode.js CLIツールでPKCE値を生成する。code_verifierはローカルに保存(例:sessionStorage)し、code_challengeは認可リクエストで送信します。