OAuthのDCR(Dynamic Client Registration)ができるまで

こんにちは。門屋です。

先日、RunbookリモートMCPサーバー(β)をリリースしたのですが、リモートMCPサーバーでユーザーの認可を実装するうえで必要なOAuthのDCR(Dynamic Client Registration)について、調べたことや検討したことについてまとめてみます。実際はMCPのAuthorization Flowをまるっと理解する必要があるのですが、範囲が広すぎるのでここではDCRについてのみ書いています。MCPのAuthorization Flowについてはいろんな方がまとめられているので、そちらも参考にしてみてください。

DCR(Dynamic Client Registration)とは?

DCRとは、認可サーバーが認可できるOAuthクライアントを自動的に登録するしくみです。通常、OAuthで認可を行うには、認可サーバーとクライアント双方で、リダイレクト先のURLやらクライアントシークレットやらの登録が必要ですが、それをクライアントからの操作だけでできるようにしましょう、というしくみです。

MCPのドキュメントによると、

MCP clients and authorization servers SHOULD support the OAuth 2.0 Dynamic Client Registration Protocol RFC7591 to allow MCP clients to obtain OAuth client IDs without user interaction.

MCPクライアントと認可サーバーは、MCPクライアントがユーザー操作なしでOAuthのクライアントIDを得るために、OAuth 2.0 Dynamic Client Registration Protocol RFC7591をサポートするべき

とあります。MUSTでなくSHOULDなので、必ずしもサポートしないといけないわけではないと読み取れるのですが、実際はMCPを提唱しているAnthropicのClaude(Web版)でクライアントIDでリモートMCPサーバーを追加しようとすると、ビジネス版のClaude for Workでないとダメだと言われてしまいます(2025/10/15現在)。つまりClaudeでリモートMCPサーバーを使うためには、DCRのサポートは実質必須といえます。

DCRはRFC7951で標準化されています。詳しい仕様が知りたい方はこちらを見てください。

DCRのフロー

大雑把に説明すると、MCPにおけるDCRのフローは次のようになります。

Authorization_-_Model_Context_Protocol.png
  1. OAuthクライアントはリソースサーバーからProtected Resourceメタデータ(.well-known/oauth-protected-resource)を取得します。ここに認可サーバーのURLが書かれています。
  2. メタデータを元に、認可サーバーからAuthorization Server メタデータ(.well-known/oauth-authorization-server)を取得します。ここにDCRのエンドポイントが書かれています。
  3. DCRのRegistrationエンドポイントにリクエストを送ります。
  4. 認可サーバーは送られた情報を元に、OAuthクライアントの情報を登録し、クライアントIDを発行します。
  5. OAuthはクライアントIDやシークレットを使って、認可サーバーに認可要求を行います。

Protected Resource メタデータの例

RFC 9728
{
"resource": "https://resource.example.com",
"resource_name": "Sample MCP server",
"authorization_servers": ["https://as1.example.com", "https://as2.example.net"],
"bearer_methods_supported": ["header"],
"scopes_supported": ["read", "write"],
"resource_documentation": "https://resource.example.com/resource_documentation.html"
}

Authorization Server メタデータの例

RFC8414
{
"issuer": "https://server.example.com",
"authorization_endpoint": "https://server.example.com/authorize",
"token_endpoint": "https://server.example.com/token",
"token_endpoint_auth_methods_supported": ["client_secret_basic"],
"registration_endpoint": "https://server.example.com/register",
"grant_types_supported": ["authorization_code", "refresh_token"],
"response_types_supported": ["code"],
"response_method_supported": ["query"],
"scopes_supported": ["read", "write"],
"code_challenge_methods_supported": ["S256", "plain"],
"ui_locales_supported": ["en-US", "ja-JP"],
"service_documentation": "http://server.example.com/service_documentation.html"
}

Registrationリクエストの例

{
"client_name": "My Example Client",
"redirect_uris": ["https://client.example.org/callback","https://client.example.org/callback2"],
"response_types": ["code"],
"grant_types": ["authorization_code","refresh_token"],
"token_endpoint_auth_method": "client_secret_basic",
"scope": "read write"
}

Registrationレスポンスの例

{
"client_id": "s6BhdRkqt3",
"client_secret": "cf136dc3c1fc93f31185e5885805d",
"client_id_issued_at": 2893256800,
"client_name": "My Example Client",
"redirect_uris": ["https://client.example.org/callback","https://client.example.org/callback2"],
"grant_types": ["authorization_code","refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "client_secret_basic",
"scope": "read write"
}

DCRのセキュリティリスク

前述のフローを見ていただくとわかるのですが、Registrationエンドポイントへの認証の仕組みについては定義されていません。RFC7591には、Registrationエンドポイントには初期アクセストークンを発行することができるが、仕様の範囲外だと書かれています。各社のMCPクライアントを見ても、初期アクセストークンについては対応が統一されておらず、現状ほぼ使えないと思ったほうがよさそうです。コンシューマー向けのサービスならさほど問題ないのかもしれませんが、エンタープライズ向けのサービスで、勝手にOAuthクライアントが登録されて他サービスからアクセスを許可されてしまっては、管理者はたまったものではありません。AtlassianなどはMCP専用の認可サーバーを用意して、まずOAuthクライアントを登録可能な管理アカウントの認可を行い、それから本来のアカウントの認可を行うといった2段構えになっているようです。

また、現在エンタープライズ向けの認可の仕組みとして、Enterprise-Managed Authorizationというものが提案されており、これを使えばOktaなどのIdPを使って一元的に認可できるらしいです。

Enterprise-Managed Authorizationについてはこちらの記事に詳しく書かれています。

Runbookでは、検討した結果、事前に管理者が許可したMCPクライアントのみDCRを受け付けることにしました。DCRではセキュリティの拠り所となるのは、リダイレクト先のURLだけなので、予めMCPクライアントごとにリダイレクト先URLをこちらで定義することで、意図しないURLにリダイレクトされないようにしています。未定義のMCPクライアントについては、ユーザーがリダイレクト先を手動で指定できるようにすることで対応します。

OAuth___Runbook.png

ユーザーの事前操作なしで利用できるDCRのメリットが半減するともいえますが、リダイレクト先URLを公開していないMCPクライアントもあるので、こうすることでユーザーの利便性を損なうことなく、セキュリティを保つことができるようになりました。

フォールバックについて

DCRに対応していないクライアントや、Registrationに失敗したときにクライアントIDでも登録できるようにしておく必要があります。

例えば、Visual Studio CodeのMCPクライアントの場合、registration_endpointがなかったり、Registrationに失敗すると、このようなダイアログが出て、クライアントIDの入力を求められます。

スクリーンショット_2025_10_15_16_56.png

PKCEについて

MCPの仕様では、MCPクライアントはPublicなクライアントであっても、Confidentialなクライアントであっても、PKCEの使用が必須となっています。

ですので、Authorization Server メタデータのcode_challenge_methods_supportedには必ず"S256"を含めなければなりません。そうでないと、MCPクライアントはそれ以降のフローを継続しません。

クライアントがPublicであるかConfidentialであるかは、Registrationリクエストのtoken_endpoint_auth_methodを見ればわかります。"none"であればPublicなクライアントであるので、クライアントシークレットをセキュアにやりとりすることができません。なのでクライアントシークレットを共有する代わりに、PKCEでcode_verifierを検証する必要があります。

Claude(Web版)で確認したところ、token_endpoint_auth_methodが"client_secret_basic"であっても、きちんとcode_challengeが送信されていました。

終わりに

MCPは仕様が策定されてから日が浅く、まだベンダー各社が手探りで実装している状況かと思います。DCRについてもまだこう実装するのが正解、というのが確立されておらず、セキュリティ上の検討事項も多いため、対応に躊躇されている方がいらっしゃるかもしれません。この記事が何かしらの参考になりましたら幸いです。

RunbookのMCPサーバーに興味を持たれた方は、こちらも読んでみてください‼️

最終更新: