PKCE
OAuth 2.0 の認可コードフローを、クライアントシークレットなしで安全に実行するための拡張
認証
PKCE とは
PKCE (Proof Key for Code Exchange、ピクシーと読む) は、RFC 7636 で定義された OAuth 2.0 の拡張で、認可コードの横取り攻撃を防ぐ仕組みである。元々はモバイルアプリや SPA など、クライアントシークレットを安全に保持できないパブリッククライアント向けに設計されたが、OAuth 2.1 では全クライアントで PKCE が必須になった。
なぜ PKCE が必要か
通常の認可コードフローでは、認可コードを横取りした攻撃者がトークンを取得できる。
1. ユーザーが認可サーバーにログイン
2. 認可サーバーがリダイレクト URL に認可コードを付与
3. ❌ 攻撃者がリダイレクトを傍受し、認可コードを横取り
4. 攻撃者が認可コードでトークンを取得
PKCE は、認可コードとトークン交換を暗号学的に紐づけることで、横取りされた認可コードを無効化する。
PKCE のフロー
1. クライアントがランダムな code_verifier を生成
2. code_verifier の SHA-256 ハッシュ = code_challenge を計算
3. 認可リクエストに code_challenge を含める
4. 認可サーバーがリダイレクトで認可コードを返す
5. トークンリクエストに code_verifier を含める
6. 認可サーバーが code_verifier のハッシュと code_challenge を照合
7. 一致すればトークンを発行
攻撃者が認可コードを横取りしても、code_verifier を知らないためトークンを取得できない。
実装
import { randomBytes, createHash } from 'crypto';
// 1. code_verifier を生成 (43〜128文字のランダム文字列)
const codeVerifier = randomBytes(32).toString('base64url');
// 2. code_challenge を計算
const codeChallenge = createHash('sha256').update(codeVerifier).digest('base64url');
// 3. 認可リクエスト
const authUrl = new URL('https://auth.example.com/authorize');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('client_id', CLIENT_ID);
authUrl.searchParams.set('redirect_uri', REDIRECT_URI);
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
// 5. トークンリクエスト (認可コード + code_verifier)
const tokenResponse = await fetch('https://auth.example.com/token', {
method: 'POST',
body: new URLSearchParams({
grant_type: 'authorization_code',
code: authorizationCode,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
code_verifier: codeVerifier, // ← これが PKCE の核心
}),
});
Cognito での PKCE
Cognito User Pool は PKCE をネイティブにサポートする。Hosted UI を使う場合、code_challenge と code_challenge_method をクエリパラメータに含めるだけでよい。
PKCE なしの認可コードフロー (非推奨)
| フロー | PKCE | クライアントシークレット | 用途 |
|---|---|---|---|
| 認可コード + PKCE | ✅ | 不要 | SPA、モバイル (推奨) |
| 認可コード + シークレット | ❌ | 必要 | サーバーサイドアプリ |
| Implicit (非推奨) | ❌ | 不要 | 廃止予定 |
Implicit フローはトークンが URL フラグメントに露出するため、OAuth 2.1 で廃止された。PKCE 付き認可コードフローが全ケースで推奨される。
PKCE を扱う関連書籍も多い。