MCP の OAuth 2.1 PKCE 対応ガイド
概要
OpenAI の Model Context Protocol (MCP) に対応するアプリケーションでは、認可フローに OAuth 2.1 の Authorization Code + PKCE を実装することが求められます。PKCE は公開クライアントでも安全に認可コードフローを利用するための仕組みで、MCP の「Deep Research」コネクタなどを動作させる上で必須となります。本記事では PKCE の基本的な流れと OAuth 2.0 との違い、/authorize・/token の各エンドポイントでの変更点を解説します。
PKCE が必須な理由
従来の認可コードフローではクライアントは固定の client_secret を使って自身を認証します。しかしブラウザやモバイルアプリのような公開クライアントでは client_secret を安全に保持できません。PKCE(Proof Key for Code Exchange)では以下の手順によってこの問題を解決します。
- 
code_verifier の生成
クライアントは 43 文字以上のランダム文字列を生成しcode_verifierとして保持します。 - 
code_challenge の生成
code_verifierを SHA-256 でハッシュし Base64URL エンコードしたものをcode_challengeとします。ハッシュ方式は常にS256を使用します。 - 
認可リクエストに code_challenge を送信
/authorizeにcode_challengeとcode_challenge_method=S256を含めてユーザー認証を行います。 - 
トークンリクエストで code_verifier を送信
認可コードを受け取った後、/tokenリクエストのボディにcode_verifierをcodeと一緒に送ります。サーバーはcode_verifierから計算したcode_challengeが初回リクエストの値と一致するか検証します。 - 
一致すればトークンを発行
code_challengeが一致すれば正規のクライアントとしてアクセストークン(必要ならリフレッシュトークン)を返します。 
この仕組みにより攻撃者が認可コードを盗んでも code_verifier を知らなければ /token でトークンを取得できません。
/authorize エンドポイントでの変更点
OAuth 2.1 では /authorize リクエストで code_challenge と code_challenge_method=S256 の送信が必須になります。例:
GET /authorize?client_id=CLIENT_ID&
    response_type=code&
    redirect_uri=CALLBACK_URL&
    scope=read%20write&
    state=STATE_VALUE&
    code_challenge=BASE64URL(SHA256(code_verifier))&
    code_challenge_method=S256
state は CSRF 対策のためのランダム値で、リダイレクト時にそのまま返却する必要があります。OAuth 2.0 では code_challenge と code_challenge_method の送信は不要でした。
/token エンドポイントでのリクエスト
PKCE フローでは /token へのリクエストに client_secret を含めず、代わりに code_verifier を送信します。
POST /token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
client_id=CLIENT_ID&
code=AUTHORIZATION_CODE&
redirect_uri=CALLBACK_URL&
code_verifier=ORIGINAL_CODE_VERIFIER
認可サーバーは code_verifier から code_challenge を再計算して検証します。リクエストヘッダに Basic 認証を付ける必要もありません。
OAuth 2.0 との主な違い
| 変更点 | OAuth 2.0 | OAuth 2.1 | 
|---|---|---|
| PKCE | 公開クライアント向けに推奨で必須ではない | すべてのクライアントで必須。code_verifier と code_challenge を必ず利用 | 
| Implicit フロー | SPAs 向けに存在しアクセストークンを直接返す | 廃止。SPAs も認可コード+PKCEを利用する | 
| Resource Owner Password Grant | ユーザーの ID・パスワードを直接送信してトークン取得が可能 | 廃止。代わりに認可コード+PKCEを使用 | 
| リダイレクトURIの一致 | ワイルドカードなど柔軟な一致が可能 | 完全一致が必須。登録済みURIと完全一致しない場合は拒否 | 
| トークンの送信方法 | クエリ文字列に含めることも許可 | クエリ文字列での送信は禁止。Authorization: Bearer ヘッダ等で送る | 
今後の実装ポイント
- MCP 対応アプリケーションでは 
/.well-known/oauth-authorization-serverと/.well-known/oauth-protected-resourceにメタデータを公開し、grant_types_supportedにauthorization_code(必要ならclient_credentials)を含める。 - 
tools_offeredには MCP の規定に沿って必要なツールのみ(searchやfetchなど)を列挙する。 - 認証されていないアクセスには 
401とWWW-Authenticateヘッダを返し、resource_metadataに/.well-known/oauth-protected-resourceの URL を示す。 - 
/tokenエンドポイントではclient_secretの代わりにcode_verifierを検証し、アクセストークンを発行する。 
まとめ
OAuth 2.1 ではすべてのクライアントで PKCE が必須となり、OpenAI MCP のような公開クライアントでも安全に認可コードフローを利用できるようになっています。/authorize で code_challenge を送信し、/token で code_verifier を検証するフローを正しく実装することで、MCP コネクタの安全な動作を実現できます。
Discussion