ID-JAGによるエンタープライズ管理認可
本ガイドでは、企業向けのMCP認可仕様の拡張であるEnterprise-Managed Authorizationについて説明します。エンタープライズIDプロバイダー(IdP)が従業員の使用可能なMCPサーバーを決定し、MCPクライアントは各サーバーでブラウザでのサインインなしにトークンを取得します。Casdoorはどちらの役割も果たせます。
- MCPサーバーの認可サーバーとして: Casdoorは、組織が信頼するエンタープライズIdPのID-JAGを受け入れます。
- エンタープライズ IdP: Casdoor は、その認可サーバーが信頼する MCP サーバーに対して ID-JAG を発行します。
学習目標
- フローと ID-JAG の概要を理解する。
- Casdoor の組織で、エンタープライズ IdP の ID-JAG を信頼させる。
- Casdoor から ID-JAG を発行する。
必要なもの
- Casdoor 管理コンソールへのグローバル管理者アクセス権
- この拡張機能をサポートする MCP クライアント(例:Okta Cross App Access を使用した Claude Team または Enterprise)
仕組み
ID-JAG (Identity Assertion JWT Authorization Grant) は、IdP が署名する短命な JWT です。これは「このユーザーはこの認可サーバーでこのクライアントを使用できます」と示します。draft-ietf-oauth-identity-assertion-authz-grant で定義されており、MCP 拡張機能 io.modelcontextprotocol/enterprise-managed-authorization はこれに基づいています。詳細は Enterprise-Managed Authorization を参照してください。
ユーザーは Casdoor のサインインページを見ることはありません。IdP がユーザーを停止した場合(例えば退職後など)、クライアントは新しい ID-JAG も新しいアクセストークンも取得できません。
Casdoor で ID-JAG を受け入れる
IdP を信頼する
-
Casdoor 管理コンソールで、User Management > Organizations に移動し、ユーザーの組織(例:
acme)を開きます。 -
オプションで Use organization issuer を有効にすると、組織独自の発行者
https://your-casdoor.com/orgs/acmeが設定されます。有効にしない場合、発行者はグローバルのhttps://your-casdoor.comになります。 -
Trusted ID-JAG issuers の下に、行を追加します:
Column Value Issuer ID-JAG の iss(例:https://acme.okta.com)JWKS URL IdP のキーセット。空欄の場合、Casdoor は <issuer>/.well-known/openid-configurationからjwks_uriを読み取りますUser 組織内でユーザーを検索する方法: {email}(デフォルト)はemailクレーム、{sub}はsubクレーム、その他の{claim}は該当するクレームを使用します。Casdoor はこれをユーザー名、メールアドレス、電話番号、ID と照合します -
組織を保存します。信頼できる発行者を変更できるのはグローバル管理者のみです。
IdP では、Casdoor に対して、ID-JAG のオーディエンスとして組織の発行者を、リソースとして MCP サーバーの URL を指定します。MCP gateway の背後にあるサーバーの場合、これは https://your-casdoor.com/api/server/acme/<server-name> です。
クライアントによるグラントの使用
クライアントは JWT ベアラートグラント(urn:ietf:params:oauth:grant-type:jwt-bearer)を使用してトークンエンドポイントで ID-JAG を交換するため、そのアプリケーションではこのグラントタイプが許可されている必要があります:
- Claude: クライアント ID メタデータドキュメント
https://claude.ai/oauth/mcp-oauth-client-metadataにグラントがリストされています。Casdoor がこのドキュメントを受け入れられるように、組織で Enable dynamic client registration を有効にしてください。詳細は Connect Claude を参照してください。 - 自分で作成したアプリケーション: Grant types に JWT Bearer を追加します。
クライアントが送信する内容
curl -X POST https://your-casdoor.com/api/login/oauth/access_token \
-d grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \
-d client_id=<client-id> \
-d client_secret=<client-secret> \
-d assertion=<ID-JAG>
Casdoor は、ID-JAG の resource をオーディエンスとするアクセストークンを返答します:
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"token_type": "Bearer",
"expires_in": 604800,
"scope": "openid profile"
}
Casdoor によるチェック項目
| チェック | ルール |
|---|---|
| タイプ | JWT ヘッダーに typ: oauth-id-jag+jwt が含まれています。他のアサーションは通常の JWT bearer grant を通ります |
| クライアント | コンフィデンシャルクライアントは、クライアントシークレットまたは private_key_jwt を使用して認証します。Claude などのクライアント ID メタデータドキュメントを使用するパブリッククライアントはシークレットを持たず、client_id のみを送信します |
| オーディエンス | aud は、独自の発行者を持つ組織の発行者、またはクライアントのアプリケーションに対応する組織を表すグローバル発行者です |
| 発行者と署名 | iss はその組織の信頼できる発行者であり、ヘッダーの kid に対応する JWKS 内のキーによって署名が検証されます |
| 有効期限 | exp と iat が存在し、有効です。1 分の猶予があります |
| クライアントバインド | client_id は、それを使用するクライアントのクライアント ID と一致します |
| 単一使用 | Casdoor は、各発行者からの jti を一度だけ受け入れます |
| ユーザー | User フィールドを通じて検索されたユーザーが組織内に存在し、禁止されておらず、クライアントのアプリケーションにサインインできる必要があります |
| スコープ | リクエスト内の scope は、ID-JAG の scope のサブセットである必要があります。指定がない場合、トークンは ID-JAG のスコープを取得します |
| リソース | resource が存在する場合、それはアクセストークンのオーディエンスになります |
自己登録したクライアント(DCR)またはクライアント ID メタデータドキュメントを使用するクライアントは、ID-JAG を使用する場合のみ JWT ベアラートグラントを利用できます。
エラー
| Error | Cause |
|---|---|
invalid_client | コンフィデンシャルクライアントが認証されませんでした |
invalid_grant | ID-JAG はいずれかのチェックに失敗しました:オーディエンスエラー、信頼できない発行者、不正な署名、期限切れ、別のクライアント宛、既に使用済み、またはユーザーが存在しない |
invalid_scope | リクエストが ID-JAG で許可されていないスコープを要求しています |
invalid_target | ID-JAG の resource が絶対 URI ではありません |
unsupported_grant_type | クライアントアプリケーションの grant types に JWT Bearer が含まれていません |
認可サーバーメタデータはサポートを通知します: grant_types_supported に urn:ietf:params:oauth:grant-type:jwt-bearer が含まれ、authorization_grant_profiles_supported に urn:ietf:params:oauth:grant-profile:id-jag が含まれます。
Casdoor から ID-JAG を発行する
Casdoor が企業の IdP である場合、クライアントは Casdoor のトークンエンドポイントでユーザーの ID トークンを ID-JAG と交換するために、トークン交換 (RFC 8693) を使用します:
curl -X POST https://your-casdoor.com/api/login/oauth/access_token \
-d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \
-d client_id=<client-id> \
-d client_secret=<client-secret> \
-d requested_token_type=urn:ietf:params:oauth:token-type:id-jag \
-d subject_token=<ID token of the user> \
-d subject_token_type=urn:ietf:params:oauth:token-type:id_token \
-d audience=https://mcp-as.example.com \
-d resource=https://mcp.example.com/mcp \
-d scope="openid profile"
{
"issued_token_type": "urn:ietf:params:oauth:token-type:id-jag",
"access_token": "eyJ0eXAiOiJvYXV0aC1pZC1qYWcrand0Ii...",
"token_type": "N_A",
"expires_in": 300,
"scope": "openid profile"
}
以下のように設定してください:
- クライアントアプリケーションの Grant types に Token Exchange を追加します。
- ユーザーの組織の LLM AI > MCP Servers ページで MCP サーバーを登録し、その URL を
resourceとして指定し、それを表す Application を選択します。resourceがない場合、Casdoor はaudience(クライアント ID またはアプリケーション名)によってアプリケーションを検索します。 - ユーザーにアクセス権限を付与します: Resource type を
Applicationに設定し、リソースとしてサーバーのアプリケーションを指定し、Effect をAllowに設定して権限を追加します。Casdoor はAllow権限が適用されるユーザーにのみ ID-JAG を発行するため、誰も権限が付与されていないアプリケーションは閉じたままになります。
ID-JAG の有効期間は 5 分です。その aud はリクエストの audience であり、client_id はリクエスト元アプリケーションのクライアント ID です。また、ユーザーの email、resource、および scope を保持します。MCP サーバーの認可サーバーは Casdoor の発行元を信頼する必要があり、クライアントはそこで同じクライアント ID(例えば、クライアント ID メタデータドキュメントの URL)を使用する必要があります。