OIDC / OAuth 2.0

認可コード + PKCE フロー

認可コードフローに PKCE(Proof Key for Code Exchange)を追加したフロー。SPAやネイティブアプリなど、client_secret を安全に保管できない環境で使用します。現在最も推奨されるフローです。

PKCE の仕組み

1

code_verifier の生成

クライアントが暗号論的に安全な43〜128文字のランダム文字列を生成します。

code_verifier = dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
2

code_challenge の計算

code_verifier の SHA-256 ハッシュを Base64URL エンコードします。

code_challenge = BASE64URL(SHA256(code_verifier))
3

認可リクエストで送信

code_challenge のみを認可サーバーに送信します。code_verifier は送信しません。

GET /authorize?...&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256
4

トークンリクエストで検証

トークン交換時に code_verifier を送信し、認可サーバーが SHA256(code_verifier) == code_challenge を検証します。

POST /token ... code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

通常の認可コードフローとの違い

項目認可コード認可コード + PKCE
クライアント認証client_secret を使用code_verifier / code_challenge を使用
対象クライアント機密クライアント(サーバーサイド)パブリッククライアント(SPA、ネイティブ)
認可コード傍受対策client_secret で保護PKCE チャレンジで保護
認可リクエスト標準パラメータのみcode_challenge, code_challenge_method を追加
トークンリクエストclient_secret を送信code_verifier を送信

シーケンス図

ブラウザ
クライアント
認可サーバー
リソースサーバー
1. PKCE パラメータ生成
>2. 認可リクエスト送信(code_challenge付き)
<3. ユーザー認証・同意
<4. 認可コードでリダイレクト
>5. トークンリクエスト(code_verifier付き)
<6. トークンレスポンス
>7. リソースアクセス

各ステップの詳細

1
PKCE パラメータ生成

クライアントクライアント

クライアントが code_verifier(ランダム文字列)を生成し、そのSHA-256ハッシュから code_challenge を計算します。

リクエスト

GENERATE (ローカル処理)

code_verifier = dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
code_challenge = E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
code_challenge_method = S256

セキュリティノート

  • !code_verifier は43〜128文字のランダム文字列
  • !code_challenge = BASE64URL(SHA256(code_verifier))
  • !S256メソッドを必ず使用する(plainは非推奨)
2
認可リクエスト送信(code_challenge付き)

ブラウザ認可サーバー

認可リクエストに code_challenge と code_challenge_method を含めて送信します。code_verifier はクライアント側で安全に保持します。

リクエスト

GET /authorize

response_type=code&client_id=my-spa-app&redirect_uri=https://example.com/callback&scope=openid profile&state=random-csrf-token&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256

セキュリティノート

  • !code_challenge のみ送信し、code_verifier は送信しない
  • !認可サーバーが code_challenge を保存する
3
ユーザー認証・同意

認可サーバーブラウザ

認可サーバーがユーザーにログイン画面と同意画面を表示します。通常の認可コードフローと同じです。

リクエスト

GET /login

レスポンス

POST /login

username=user&password=****&consent=approve

セキュリティノート

  • !通常の認可コードフローと同じ認証プロセス
4
認可コードでリダイレクト

認可サーバークライアント

認可サーバーが認可コード付きでリダイレクトします。通常の認可コードフローと同じです。

リクエスト

GET https://example.com/callback

code=SplxlOBeZQQYbYS6WxSbIA&state=random-csrf-token

セキュリティノート

  • !認可コード単体では不十分。code_verifier が必要
5
トークンリクエスト(code_verifier付き)

クライアント認可サーバー

クライアントが認可コードと一緒に code_verifier を送信します。認可サーバーは保存していた code_challenge と照合して検証します。

リクエスト

POST /token

Content-Type: application/x-www-form-urlencoded

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

セキュリティノート

  • !client_secret の代わりに code_verifier で証明
  • !認可サーバーは SHA256(code_verifier) == code_challenge を検証
  • !認可コードを傍受されても code_verifier がなければトークンを取得できない
6
トークンレスポンス

認可サーバークライアント

PKCE検証に成功すると、認可サーバーがアクセストークンを返します。

リクエスト

POST /token

レスポンス

200 /token

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid profile"
}

セキュリティノート

  • !パブリッククライアントのためリフレッシュトークンは返さない場合が多い
7
リソースアクセス

クライアントリソースサーバー

取得したアクセストークンでリソースサーバーにアクセスします。

リクエスト

GET /api/userinfo

Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

セキュリティノート

  • !通常の認可コードフローと同じリソースアクセス
使うべき場面
  • +SPA(シングルページアプリケーション)
  • +モバイル/ネイティブアプリケーション
  • +client_secret を安全に保管できないパブリッククライアント
  • +現在最も推奨されるフロー(RFC 7636、OAuth 2.1)
使うべきでない場面
  • -サーバー間通信 → クライアントクレデンシャルフローを使用
  • -入力デバイスがないIoT → デバイス認可フローを使用

セキュリティ上の考慮事項

  • !code_challenge_method は必ず S256 を使用する
  • !code_verifier は暗号論的に安全な乱数で生成する
  • !code_verifier はリクエストごとに新規生成する
  • !インプリシットフローの代わりにこのフローを使用すること
  • !state パラメータも併用して CSRF を防止する