🔐

Python × Microsoft Entra ID で学ぶ OAuth 2.0 OBO フロー [最小実装サンプル付き]

に公開

はじめに

マイクロサービスやBFF構成で「ユーザーの代わりに下流APIを呼びたい」という要件はよくあります。
Microsoft Entra ID(旧Azure AD)では、OAuth 2.0の On-Behalf-Of(OBO)フローを使うことで、ユーザーの認証情報を安全に引き継ぎながらAPI連携が可能です。

本記事では以下を解説します:

  • OBOフローの仕組み
  • Python(Flask + MSAL)による最小実装
  • 処理シーケンス図(Mermaid対応)
  • 誤りやすいパターンと対策
  • セキュリティベストプラクティス

OBOフローとは?

OBOフローは、「あるサービス(バックエンド)が、ユーザーの代わりに別のサービス(下流API)を呼び出す」 ための仕組みです。

典型的なシナリオ:

  • フロントエンド(SPAやWebアプリ) がユーザーを認証し、バックエンドAPIにアクセス
  • バックエンドAPIは受け取った ユーザーのアクセストークン を使って Microsoft Graphや社内API を呼び出す(実際にはOBOで新しい下流API用ATを発行して使用)

Pythonでの最小実装(概要)

  • frontend_app(Flask)
    認可コードフローでサインイン → api://<BACKEND>/access_as_userATを取得 → バックエンドAPIへ
  • api_app(Flask)
    msal.ConfidentialClientApplication.acquire_token_on_behalf_of(...)Graphの委任スコープ(例:User.Read) を要求 → /v1.0/me を呼ぶ

実装コードは GitHubリポジトリ(https://github.com/naokky-tech/sample-oboflow) を参照。


サンプル実装

OBOフローの処理シーケンス


✅ Azure Portal 設定手順

目的

  • フロントエンド用アプリ(public / SPA 可)
  • バックエンド API 用アプリ(confidential)を 1 テナント内に登録し、OBO に必要なカスタムスコープ access_as_user を発行します。

1-1. バックエンド API アプリを登録する

  • 同様に アプリの登録 で作成
    API アプリ概要

  • アプリケーション (クライアント) IDディレクトリ (テナント) ID をメモ
    アプリ概要

1-2. バックエンド API の公開 → カスタムスコープを作成

  • カスタムスコープの設定
    API の公開 – access_as_user スコープ
  1. API の公開 → 「Scope の追加」
  2. Scope 名を access_as_user に設定
  3. 同意の表示名・説明は「ユーザーのアクセス権限による検索」など任意
  4. 保存して続行

1-3. バックエンド API が利用して良いGraphAPIの権限(スコープ)を追加する

  • GraphAPI権限設定
    API アクセス許可 – GraphAPIの権限追加
  1. API のアクセス許可アクセス許可の追加
  2. 利用したいGraphAPIの権限 をチェック(サンプル実装ではUser.Readのみ利用)
  3. アクセス許可の追加 をクリック
  4. (組織テナントなら)管理者の同意 を与えておく

1-4. バックエンド API用のクライアント シークレットを作成

  • クライアントシークレット
    証明書とシークレット – クライアント シークレット
  1. 証明書とシークレット新しいクライアント シークレット
  2. 説明と有効期限を設定し 追加
  3. 生成直後に表示される をメモ(再表示不可)

メモを忘れた場合は 新しくシークレットを作り直してください。
.envBACKEND_CLIENT_SECRET= に貼り付けます。


2-1. 新しいアプリを登録する(フロントエンド)

  • フロントエンドのアプリ登録
    新規アプリ登録
  1. アプリの登録新規登録
  2. 任意の名前を入力
  3. 「この組織…シングルテナント」を選択
  4. リダイレクト URI は空で OK(後で追加可能) ※demoではローカル端末でフロントエンドのアプリを実行するため "http://localhost:5000/auth/redirect" として登録(実装に合わせる)
  5. 登録をクリック

2-2. フロントエンドにスコープを付与

  • バックエンドAPIのスコープ付与
    API アクセス許可 – access_as_user 追加
  1. API のアクセス許可アクセス許可の追加
  2. <APIアプリ名>」→ access_as_user をチェック
  3. アクセス許可の追加 をクリック
  4. (組織テナントなら)管理者の同意 を与えておく

✅ pythonでサンプルアプリ実装

gitからクローンしてお試しください。

1. リポジトリをクローン

git clone https://github.com/naokky-tech/sample-oboflow.git
cd sample-oboflow

2. 手順に従い実行

詳細な手順はgitを参照ください。
https://github.com/naokky-tech/sample-oboflow

  • 仮想環境を作成して有効化
  • 依存パッケージをインストール
  • .env ファイルの設定
  • 起動と動作確認

動作させると以下のようにUser.Readの権限に基づいた情報が取得できていることが確認できます。
API アクセス許可 – access_as_user 追加


OBOフローのはまりポイント

OBOで使えないケース

  • カスタム署名キーを使うアプリ
  • ワイルドカードReply URL + id_token
  • App-onlyトークンをassertionに使用(OBOはユーザー主体のみ)

よくある落とし穴と対策

誤り 症状 対処
IDトークンを渡す invalid_grant アクセス トークン(aud=バックエンド) を渡す
フロントでGraphスコープ要求 aud不一致 フロントは access_as_user、Graphはバックエンドで要求
バックエンドにGraph権限なし insufficient privileges バックエンドに User.Read を付与+管理者同意
SPAでOBO実行 認証エラー 機密クライアント(バックエンド)で実行
OBOトークンをクライアントに返却 セキュリティリスク データのみ返却

セキュリティベストプラクティス

  • トークンを中継しない(バックエンドでデータのみ返却)
  • 条件付きアクセスやMFA対応interaction_required エラーを処理
  • aud不一致を防ぐ → スコープは完全修飾名(api://<client-id>/<scope>)で指定

まとめ

  • OBOは、ユーザー主体の安全なAPI委任を実現する中核パターン
  • Python + MSAL で手早く実装できる
  • IDトークン誤用/スコープ設定ミス/権限・同意不足が典型的なハマりどころ
  • 設計時は 「誰がどのスコープでどのトークンを取得するか」 を明確に

参考リンク

  • Microsoft identity platform と OAuth 2.0 OBO フロー(公式ドキュメント) (Microsoft Learn)
  • MSAL for Python ドキュメント (Microsoft Learn)
  • MSAL Python OBO サンプル(GitHub) (GitHub)
  • Microsoft Graph 権限リファレンス (Microsoft Learn)

Discussion