シングルページアプリケーション(SPA)向けPKCE

シングルページアプリケーションでOAuth 2.0認可コード + PKCEを実装する方法。code_verifierとcode_challenge生成のコード例付きステップバイステップガイド。

PKCE

詳細な説明

シングルページアプリケーション向けPKCE

PKCE(Proof Key for Code Exchange、「ピクシー」と発音)は、パブリッククライアント(client_secretを安全に保存できないアプリケーション、ブラウザベースのSPA、モバイルアプリ、デスクトップアプリケーションなど)に対して認可コードフローを安全にする拡張機能です。

SPAにPKCEが必要な理由

SPAは完全にブラウザ内で実行されるため:

  • client_secretを安全に保存できない(JavaScriptの秘密はユーザーがアクセス可能)
  • 認可コードが悪意のあるブラウザ拡張機能やオープンリダイレクターを通じて傍受される可能性
  • インプリシットフロー(旧代替手段)はトークンをURLに直接公開

PKCEは、フローを開始したクライアントがコードを交換するクライアントと同一であることの暗号証明を追加することで、認可コードの傍受問題を解決します。

PKCEの仕組み

1. code_verifierを生成 — ランダム文字列(43-128文字):

const array = new Uint8Array(32);
crypto.getRandomValues(array);
const code_verifier = base64url(array);

2. SHA-256でcode_challengeを導出

const encoder = new TextEncoder();
const digest = await crypto.subtle.digest(
  "SHA-256",
  encoder.encode(code_verifier)
);
const code_challenge = base64url(new Uint8Array(digest));

3. 認可リクエスト — チャレンジを含める:

GET /authorize?response_type=code
  &client_id=spa-client
  &redirect_uri=https://app.example.com/callback
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
  &scope=openid profile
  &state=random-state

4. トークン交換 — 元のverifierを含める:

POST /token
grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://app.example.com/callback
&client_id=spa-client
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

認可サーバーがSHA256(code_verifier)を計算し、保存されたcode_challengeと比較します。一致すればトークンが発行されます。

ベストプラクティス

  • 常にS256を使用(plainは使用しない)
  • code_verifierをsessionStorageに保存(タブ閉鎖時にクリア)
  • 認可リクエストごとに新しいcode_verifierを使用
  • 多層防御のためにPKCEとstateパラメータを組み合わせる

ユースケース

OAuth 2.0プロバイダー(Auth0、Okta、Azure ADなど)を介してユーザーを認証するReact、Vue、AngularのSPA。アプリがログインページへのリダイレクト前にPKCEペアを生成し、トークン交換時にcode_verifierを使用します。

試してみる — OAuth 2.0 Flow Visualizer

フルツールを開く