Open26

MCPの認可仕様 (6/18) に従ったMCPサーバーを作る。認可サーバーにはAuth0を使ってみたい。

tetsuzawatetsuzawa

まずは仕様を読んでみて重要そうなポイントをメモしてみる

標準準拠
この認証メカニズムは、以下にリストされている確立された仕様に基づいていますが、シンプルさを維持しながらセキュリティと相互運用性を確保するために、選択された機能のサブセットを実装しています。

  • OAuth 2.1 IETF ドラフト ( draft-ietf-oauth-v2-1-12 )
  • OAuth 2.0 認可サーバーメタデータ ( RFC8414 )
  • OAuth 2.0 動的クライアント登録プロトコル ( RFC7591 )
  • OAuth 2.0 保護リソースメタデータ ( RFC9728 )
tetsuzawatetsuzawa

https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#roles

保護されたMCP サーバーは、アクセス トークンを使用して保護されたリソース要求を受け入れ、応答できるOAuth 2.1 リソース サーバーとして機能します。

MCPサーバーはリソースサーバーなので、RFC9728の OAuth 2.0 Protected Resource Metadata の仕様を参考にする必要がありそう

MCPクライアントはOAuth 2.1 クライアントとして機能し、リソース所有者に代わって保護されたリソース要求を行います。

MCPクライアントはこのスクラップの主題ではないので後で必要があれば見ていく。

Inspector や cursor, vscodeが対応していると嬉しい。
(おそらくだがvscodeは 6/18 のバージョンの仕様に従っているはず。 GitHub Remote MCPのリリースノート から読み取る限りではあるが。(仕様のリンクの参照先がdraftとなっていて、当時のdraft = 6/18 アップデートの内容のはず)

tetsuzawatetsuzawa

https://zenn.dev/su8/articles/fcb3b8b3f5439f#oauth-resource-server分類とprmの実装義務化

Protected Resource Metadata(PRM)は以下の重要な役割を持つ。

  1. 認証サーバーの場所情報提供(authorization_serversフィールド)
  2. サーバー自身のリソース識別子の明示(resourceフィールド)
  3. サポートされるスコープの公開(scopes_supportedフィールド)
    MCPクライアント側も、PRM文書に基づいて認証サーバーを発見することが必須となった。
tetsuzawatetsuzawa

https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#authorization-server-location

MCP servers MUST implement the OAuth 2.0 Protected Resource Metadata (RFC9728) specification to indicate the locations of authorization servers. The Protected Resource Metadata document returned by the MCP server MUST include the authorization_servers field containing at least one authorization server.

MCPサーバーが OAuth 2.0 Protected Resource Metadata を実装するのは必須

URLは GET /.well-known/oauth-protected-resource

tetsuzawatetsuzawa

MCP servers MUST use the HTTP header WWW-Authenticate when returning a 401 Unauthorized to indicate the location of the resource server metadata URL as described in RFC9728 Section 5.1 “WWW-Authenticate Response”.

フローの最初で 401 のステータスとともに WWW-Authenticate ヘッダ に resource server metadata URL を乗せるのが必須
https://datatracker.ietf.org/doc/html/rfc9728#name-www-authenticate-response


https://datatracker.ietf.org/doc/html/rfc9728#section-5.1-4

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://resource.example.com/.well-known/oauth-protected-resource"
tetsuzawatetsuzawa

https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#token-handling

MCP servers, acting in their role as an OAuth 2.1 resource server, MUST validate access tokens as described in OAuth 2.1 Section 5.2. MCP servers MUST validate that access tokens were issued specifically for them as the intended audience, according to RFC 8707 Section 2. If validation fails, servers MUST respond according to OAuth 2.1 Section 5.3 error handling requirements. Invalid or expired tokens MUST receive a HTTP 401 response.

MCP servers MUST NOT accept or transit any other tokens.

アクセストークンのハンドリング(上図の最後の部分)についてさらに細かく見ると4つポイントがある

  1. OAuth 2.1 リソースサーバーとして機能する MCP サーバーは、OAuth 2.1 セクション 5.2に記載されているようにアクセストークンを検証する 必要があります。

    アクセス トークンを受け取った後、リソース サーバーは、アクセス トークンの有効期限が切れていないこと、要求されたリソースへのアクセスが承認されていること、適切なスコープで発行されていること、保護されたリソースにアクセスするためのリソース サーバーのその他のポリシー要件を満たしていることを確認する必要があります。
    アクセストークンは一般的に、参照トークンと自己エンコードトークンの2つのカテゴリに分類されます。参照トークンは、認可サーバーにクエリを実行するか、トークンデータベースでトークンを検索することで検証できます。一方、自己エンコードトークンには、リソースサーバーが抽出できる暗号化および/または署名された文字列に認可情報が含まれています。
    アクセストークンの有効性を確認するために認可サーバーに問い合わせる標準化された方法は、トークンイントロスペクション[ RFC7662 ]で定義されています。
    トークン文字列内の情報をエンコードする標準化された方法は、アクセストークンのJWTプロファイル[ RFC9068 ]で定義されています。

    1. 画像
      (不確実) Auth0は opaque トークン をデフォルトで発行するが、インストロペクションエンドポイントを持っていない
    2. 画像
      (不確実)Auth0は JWTアクセストークン(self‑encoded token)を発行しており 自己検証できる
    3. アクセス トークンの作成と検証に関する追加の考慮事項については、セクション 7.1を参照してください。
      1. セキュリティ等に関する留意事項が書かれていた
      2. ある程度知っている内容なので割愛
        3. 気になったのは https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-12#section-7.1.4 dが一旦メモに止める
  2. また、 RFC 8707 セクション 2に従い、 MCP サーバーはアクセストークンが対象ユーザーとして自身に発行されたことを検証する必要があります

  3. 検証に失敗した場合、サーバーはOAuth 2.1 セクション 5.3 の エラー処理要件に従って応答する 必要があります。無効または期限切れのトークンは、HTTP 401 レスポンスを受け取る必要があります

  1. MCP サーバーは他のトークンを受け入れたり転送したりしてはなりません。
tetsuzawatetsuzawa

https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#authorization-code-protection

To mitigate this, MCP clients MUST implement PKCE according to OAuth 2.1 Section 7.5.2. PKCE helps prevent authorization code interception and injection attacks by requiring clients to create a secret verifier-challenge pair, ensuring that only the original requestor can exchange an authorization code for tokens.

vscodeはGitHubリモートMCPのリリースノート公開時点でまだPKCE対応してないって言っていた記憶
今後対応するって書いてあったので一時的に仕様から準拠できていない状態でリリースしてるのか
準拠すべきではあるけど小さくリリースするという点で参考になる

tetsuzawatetsuzawa

https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#open-redirection

MCP クライアントは、認可サーバーに登録されたリダイレクト URI を持っている必要があります。

認可サーバーは、リダイレクト攻撃を防ぐために、事前に登録された値に対して正確なリダイレクト URI を検証する必要があります。

MCP クライアントは、認可コード フローで状態パラメータを使用して検証し、元の状態が含まれていない、または元の状態と一致しない結果を破棄する必要があります。

これ気になるなー
Auth0 使うならリダイレクトURI はMCPクライアントが動くlocalhostになる?
Auth0ってローカルホストをリダイレクトURIとして指定できたっけ?
なんかここに関しては理解できていない可能性が高い

tetsuzawatetsuzawa

https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization#confused-deputy-problem

攻撃者は、サードパーティAPIへの仲介役として機能するMCPサーバーを悪用し、Confused Deputy脆弱性を悪用する可能性があります。盗んだ認可コードを使用することで、ユーザーの同意なしにアクセストークンを取得できます。
静的クライアント ID を使用する MCP プロキシ サーバーは、サードパーティの認証サーバーに転送する前に、動的に登録されたクライアントごとにユーザーの同意を取得する必要があります(追加の同意が必要になる場合があります)。

これもMUST とされてるけど、一旦実装しなくていい気がするな

tetsuzawatetsuzawa

https://zenn.dev/su8/articles/fcb3b8b3f5439f#rfc-8707リソースインジケータの検証プロセス

リソースインジケータがあると、悪意のあるMCPサーバーによってアクセストークンが使われるのを防げるっぽい?
ちょっと理解できていない。
悪意のあるMCPサーバーにトークン検証するかしないかが委ねられるなら検証せずに使われるのでは?
(理解できていないので後でもっと調べる)

tetsuzawatetsuzawa

expressじゃなくてhonoで実装したいので、ミドルウェアは ↑を書き写して書いてもいいかも?
hono使いたいのはただの趣味
一旦expressでも全然よいが

tetsuzawatetsuzawa
tetsuzawatetsuzawa

メモ
一旦のTODO

  • Auth0を認可サーバーとしたときの各種設定を調べる
    • 実際に実装していくときは Auth0での実装も考えていかなくてはならない
  • テスト用のMCP Clientが最新仕様に追従できているものがあるか調べる
    • inspectorはまだ対応指定なさそう?と思ったが触ってみないとわからない
tetsuzawatetsuzawa

AIに入力してリファインメントするために、実装するときの前提を書き出していく

  • 認可サーバーはAuth0を使う
  • MCPサーバーのデプロイ先はcloudflareを使う
  • タスクの進め方(今の想定)
    • シンプルなwebサーバーをcloudflareにデプロイする
    • ブラウザでアクセスできるかテスト
    • シンプルなMCPサーバーをcloudflareにデプロイする
    • MCP Inspectorやcursorで接続してテスト
    • MCPサーバーに 認可フローの機構を実装する
    • MCP Inspectorやcursorで接続してテスト
tetsuzawatetsuzawa

現状の知見

  • cloudflare workersで動かそうとするとMCPが使えない
  • honoに書き換えるために、書き写すといったことをある程度行っている