1. 主要ページへ移動
  2. メニューへ移動
  3. ページ下へ移動

QES ブログ

記事公開日

API Management×Graph API - OBOフローでMCPのユーザー情報を拡張してみた -

  • このエントリーをはてなブックマークに追加

この記事のポイント

API ManagementでJWT認証を行う構成をベースに、Graph APIのOBO(On-Behalf-Of)フローを組み合わせることで、MCPサーバーからユーザーの詳細プロファイルを取得できるようにしました。

  • JWTクレームだけでは取れない情報がある:
    アクセストークンに含まれるのは基本情報(名前・メール・ID)のみ。役職・部署などの詳細はGraph APIから取得する必要がある
  • OBOフローでトークンを交換:
    ユーザーのアクセストークンをGraph API用トークンに交換することで、ユーザーに代わってGraph APIを呼び出せる
  • OBOには事前の同意付与が必要:
    Microsoft Foundryの承認画面ではGraph APIへの同意が含まれないため、テナント管理者による事前付与(管理者同意)が確実

こんにちは!DXソリューション営業本部の大和矢です。

前回の記事では、API ManagementのConsumption tierを使って、MCPサーバーをEntra IDのJWT認証で保護する構成を紹介しました。

この構成では、JWTのクレーム(ペイロードに含まれる情報)から、ユーザーの名前やメールアドレスを取得できました。
しかし、役職・部署・電話番号といった詳細なプロファイル情報は、JWTには含まれていません。

今回は、Graph APIのOBO(On-Behalf-Of)フローを組み合わせることで、MCPサーバーからユーザーの詳細プロファイルまで取得できるようにした拡張構成を紹介します。
前回の認証フローを変更せず、最小限の追加で拡張できる点もポイントです。
前回と同様、最終的にはAI開発プラットフォームのMicrosoft FoundryからMCPサーバーを呼び出し、動作を確認します。

JWTクレームの限界

前回の構成では、API ManagementがJWTを検証した後、トークンのクレーム(ペイロード)からユーザー情報を抽出してAzure Functionsに転送していました。
この方式はシンプルで追加のAPI呼び出しも不要ですが、取得できる情報はJWTに含まれるものに限られます

取得方法 取得できる情報 追加のAPI呼び出し
JWTクレーム(前回) 名前・メール・オブジェクトID 不要
Graph API OBO(今回) 役職・部署・電話番号など詳細情報 あり

「誰がアクセスしたか」を識別するだけならJWTクレームで十分です。
しかし、ユーザーの所属や役職に応じて振る舞いを変えたいといったケースでは、より詳細な情報が必要になります。
そこで登場するのが、今回紹介するOBOフローです。

OBOフローとは

OBO(On-Behalf-Of)フローは、ユーザーに代わって別のAPIを呼び出すための仕組みです。
Microsoft IDプラットフォームが標準でサポートしており、仕様の詳細はMicrosoft公式ドキュメントにまとまっています。

ユーザーがMCPサーバーにアクセスする際に取得したトークンは、MCPサーバー宛に発行されたものです。
このトークンをそのままGraph APIに送っても、宛先(audience)が異なるため拒否されてしまいます。

そこでOBOフローでは、MCPサーバー宛のトークンをEntra IDに提示して、Graph API用のトークンに交換します。
このとき、アプリが「本物である」ことを証明するためにクライアントシークレットを一緒に提示します。
交換後のトークンは元のユーザーの権限を引き継いでいるため、ユーザーに代わってGraph APIの /me エンドポイントを呼び出し、詳細なプロファイル情報を取得できます。

OBOフローによるGraph APIトークンの取得と呼び出しの詳細図。Azure FunctionsがユーザーのJWTとクライアントシークレットをEntra IDに提示し、Graph API用トークンを取得して/meエンドポイントを呼び出す

図の左下にあるように、もしGraph APIへの同意(権限付与)がない状態でトークン交換を行うと、ここでエラーになります。
このエラーを避けるための「管理者同意」については、後ほど詳しく説明します。

なぜトークンを交換する必要があるのか:
OAuth2の仕組みでは、トークンには「誰宛のトークンか」を示すaudience(宛先)が設定されています。
MCPサーバー宛のトークンとGraph API宛のトークンはaudienceが異なるため、直接使い回すことはできません。
OBOフローは、この制約を安全に解決するための標準的な仕組みです。

拡張後のアーキテクチャ

今回の構成の全体像は以下の通りです。
前回と同じく、クライアントとMCPサーバーの間にAPI Management(Consumption tier)を配置し、その奥のAzure FunctionsがOBOフローでGraph APIを呼び出します。

拡張後の全体アーキテクチャ図。クライアントからEntra ID、API Management(Consumption tier)、Azure Functions(MCPサーバー)を経由し、whoami_graphツールがOBOフローでMicrosoft Graph APIを呼び出してユーザープロファイルを取得する構成

前回の構成からの変更点はシンプルです。
API ManagementのポリシーにユーザーのJWTをそのままカスタムヘッダーに退避する処理を1つ追加し、Azure Functions側にOBOフローを実行するツールを追加しただけです。

処理の流れは以下の通りです。

  1. API ManagementがユーザーのJWTを検証する(前回と同じ)
  2. ユーザー情報をカスタムヘッダーに退避する(前回と同じ)
  3. ユーザーのJWTそのものを別のカスタムヘッダーに退避する(今回追加)
  4. AuthorizationヘッダーをマネージドIDのトークンに差し替えてAzure Functionsに転送する(前回と同じ)
  5. Azure Functionsが退避されたJWTを取り出し、OBOフローでGraph API用トークンに交換する
  6. Graph API /me を呼び出し、ユーザーの詳細プロファイルを取得する

この一連の流れを、フェーズごとに図にすると以下のようになります。

OBOフローによるGraph API連携の一連の流れ図。JWT取得、API Managementでの検証とトークン退避、Azure FunctionsでのOBOトークン交換、Graph API呼び出しという4つのフェーズと、JWTクレーム方式とGraph API OBO方式の比較

前回の構成に対する追加は最小限で、既存の認証フローを変更せずに拡張できている点がポイントです。
また、MCPサーバーには複数のツールを用意できますが、Graph APIを呼び出すのはGraph API連携が必要なツールが実行されたときだけです。
ユーザーの識別だけで足りるツールではGraph APIは呼ばれないため、必要なときにだけGraph APIへアクセスする、無駄のない構成になっています。

ポリシーの実装ポイント:ユーザートークンの退避

今回の拡張で鍵になるのが、ユーザーのJWTをAzure Functionsまで届ける仕組みです。

API Managementは、Azure Functionsに転送する直前にAuthorizationヘッダーをマネージドIDのトークンへ差し替えてしまいます。
そのままではユーザーのJWTがAzure Functionsに届かず、OBOフローのトークン交換ができません。
そこで、トークンが差し替えられる前に、ユーザーのJWTを X-Original-Token というカスタムヘッダーに退避しておきます。

X-Original-Tokenによるユーザートークンの退避とOBO利用のポリシー詳細図。API Managementのinbound処理でvalidate-jwt、set-header(X-Original-TokenにユーザーのJWTを退避)、authentication-managed-identityの順に処理し、Azure Functions側でX-Original-Tokenを取り出してOBOフローに利用する

ポリシーの配置順序は重要です。
JWTの検証 → X-Original-Tokenへの退避 → マネージドIDトークンへの差し替え、という順序を守る必要があります。
退避を差し替えより後に書いてしまうと、ユーザーのJWTが失われてしまうため注意してください。

<!-- authentication-managed-identity の直前に配置 -->
<set-header name="X-Original-Token" exists-action="override">
  <value>@(context.Request.Headers.GetValueOrDefault("Authorization", "").Replace("Bearer ", ""))</value>
</set-header>

Azure Functions側では、この X-Original-Token からユーザーのJWTを取り出し、MSAL(Microsoft Authentication Library)を使ってOBOフローのトークン交換を実行します。

cca = msal.ConfidentialClientApplication(
    client_id=client_id,
    authority=f"https://login.microsoftonline.com/{tenant_id}",
    client_credential=client_secret,
)
result = cca.acquire_token_on_behalf_of(
    user_assertion=original_token,
    scopes=["https://graph.microsoft.com/User.Read"],
)

管理者同意を採用する理由

OBOフローは、バックエンドでのヘッダレスなトークン交換のため、同意画面を表示できません。
そのため事前に同意を済ませておく必要があり、テナント全体へ一括付与できる管理者同意(admin-consent)が最も確実です。
なお User.Read 自体はユーザー自己同意も可能な低権限ですが、OBOでは対話的な同意ができないため、管理者同意での事前付与を採用しています。
具体的な付与手順はMicrosoft公式ドキュメントにまとまっています。

Foundryの承認画面でカバーされる範囲

FoundryからMCPサーバーに接続する際、Entra IDの承認画面が表示されます。
しかし、ここでユーザーが同意するのはMCPサーバーへのアクセス権限のみです。
Graph APIへのアクセス権限(User.Read)は、この承認フローには含まれていません。

自前のクライアントであれば、同意画面に中間層API側のGraph権限までまとめて含める設定(.defaultを使った組み合わせ同意)も可能です。
しかし、Foundryのような外部クライアントではこの設定ができないため、テナント管理者による事前付与が現実的な選択肢になります。

項目 管理者同意あり 管理者同意なし
MCPツールの呼び出し 正常 正常
OBOフロー(Graph API呼び出し) 正常 失敗

管理者同意がない状態でOBOフローを実行すると、Graph APIへの同意が存在しないため、トークン交換時にエラーが発生します。
これは「OBOフローとは」のトークン交換図でも示した、同意なしの場合のエラーにあたります。
筆者も検証中にこのエラーに遭遇し、管理者同意を付与することで解決しました。

運用上のポイント:
管理者同意は、テナント内の全ユーザーに対してGraph API権限を一括で付与するものです。
セットアップ時に一度だけ実行すればよく、個々のユーザーが追加で同意操作を行う必要はありません。

検証:Foundryからの呼び出し

実際にFoundryからMCPサーバーに接続し、Graph APIを使ったユーザー情報取得ツール(whoami_graph)を呼び出してみます。

前回紹介したJWTクレーム方式(whoami)では、名前・メールアドレス・オブジェクトIDが取得できました。
今回のGraph API OBO方式(whoami_graph)では、それらに加えて部署などの詳細プロファイルまで取得できるかが確認のポイントです。

whoami_graphツールを呼び出した結果。Graph APIから氏名・メールアドレス・UPN・部署・使用地域・ユーザーIDなどのプロフィールが取得でき、未設定の項目(役職・会社名など)も表示されている画面

「Graph API 取得結果」として、氏名・メールアドレス・UPN・部署・使用地域などが返ってきています。
OBOフローが正しく動作し、ユーザーに代わってGraph APIを呼び出せていることが確認できました。
JWTクレーム方式では取得できなかった部署などの詳細情報まで取れている点が、今回の構成のメリットです。

一方で、役職や会社名などは「未設定」と表示されています。
これは、このユーザーのEntra IDプロファイルにそれらの情報が登録されていないためです。
Graph APIで取得できるのは、あくまでEntra ID上に登録されている情報に限られる点に注意してください。

まとめ:用途に応じた使い分け

今回の検証で、OBOフローによるGraph APIからの詳細ユーザープロファイル取得が正常に動作することを確認できました。

2つの方式の使い分けをまとめます。

観点 JWTクレーム方式 Graph API OBO方式
取得できる情報 名前・メール・ID 役職・部署・電話番号なども
情報の鮮度 トークン発行時点 API呼び出し時点の最新
追加設定 不要 Graph API権限・管理者同意・クライアントシークレット
おすすめケース ユーザー識別ができれば十分 役職や部署に応じた処理が必要

どちらの方式も同じ認証基盤の上に成り立っており、用途に応じて選択・併用できます。
基本はJWTクレーム方式で十分ですが、より詳細なユーザー情報が必要になったときにOBOフローを追加する、という段階的な導入が可能です。

一方で、OBOフローにはクライアントシークレットの管理事前の同意付与という運用上の前提が伴います。
シークレットはKey Vaultなどで安全に管理し、同意はセットアップ時に管理者同意でまとめて付与しておくと安定運用につながります。
必要になったときに無理なく拡張できるよう、まずはJWTクレーム方式から始めてみてはいかがでしょうか。

QUICK E-Solutionsでは、AIを活用した業務効率化・システム導入のお手伝いをしております。
それ以外でも QESでは様々なアプリケーションの開発・導入を行っております。提供するサービス・ソリューションにつきましては こちら に掲載しております。
システム開発・構築でお困りの問題や弊社が提供するサービス・ソリューションにご興味を抱かれましたら、ぜひ一度 お問い合わせ ください。

※このブログで参照されている、Microsoft、Azure、Azure API Management、Azure Functions、Entra ID、Microsoft Graph APIは、米国Microsoft Corporationの米国およびその他の国における商標または登録商標です。

  • このエントリーをはてなブックマークに追加

お問い合わせ

Contact

ご質問やご相談、サービスに関する詳細など、何でもお気軽にご連絡ください。下記のお問い合わせフォームよりお気軽に送信ください。

お問い合わせ

資料ダウンロード

Download

当社のサービスに関する詳細情報を掲載した資料を、下記のページよりダウンロードいただけます。より深く理解していただける内容となっております。ぜひご活用ください。

資料ダウンロード