🔐

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)では以下の手順によってこの問題を解決します。

  1. code_verifier の生成
    クライアントは 43 文字以上のランダム文字列を生成し code_verifier として保持します。
  2. code_challenge の生成
    code_verifier を SHA-256 でハッシュし Base64URL エンコードしたものを code_challenge とします。ハッシュ方式は常に S256 を使用します。
  3. 認可リクエストに code_challenge を送信
    /authorizecode_challengecode_challenge_method=S256 を含めてユーザー認証を行います。
  4. トークンリクエストで code_verifier を送信
    認可コードを受け取った後、/token リクエストのボディに code_verifiercode と一緒に送ります。サーバーは code_verifier から計算した code_challenge が初回リクエストの値と一致するか検証します。
  5. 一致すればトークンを発行
    code_challenge が一致すれば正規のクライアントとしてアクセストークン(必要ならリフレッシュトークン)を返します。

この仕組みにより攻撃者が認可コードを盗んでも code_verifier を知らなければ /token でトークンを取得できません。

/authorize エンドポイントでの変更点

OAuth 2.1 では /authorize リクエストで code_challengecode_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_challengecode_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_verifiercode_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_supportedauthorization_code(必要なら client_credentials)を含める。
  • tools_offered には MCP の規定に沿って必要なツールのみ(searchfetch など)を列挙する。
  • 認証されていないアクセスには 401WWW-Authenticate ヘッダを返し、resource_metadata/.well-known/oauth-protected-resource の URL を示す。
  • /token エンドポイントでは client_secret の代わりに code_verifier を検証し、アクセストークンを発行する。

まとめ

OAuth 2.1 ではすべてのクライアントで PKCE が必須となり、OpenAI MCP のような公開クライアントでも安全に認可コードフローを利用できるようになっています。/authorizecode_challenge を送信し、/tokencode_verifier を検証するフローを正しく実装することで、MCP コネクタの安全な動作を実現できます。

株式会社トッカシステムズ

Discussion