演習 - OAuth で保護された API と API プラグインを統合する

完了

Microsoft 365 Copilot用の API プラグインを使用すると、OAuth で保護された API と統合できます。 API を保護するアプリのクライアント ID とシークレットは、Teams コンテナーに登録することでセキュリティで保護します。 実行時に、Microsoft 365 Copilotはプラグインを実行し、コンテナーから情報を取得し、それを使用してアクセス トークンを取得し、API を呼び出します。 このプロセスに従うことで、クライアント ID とシークレットはセキュリティで保護され、クライアントに公開されることはありません。

サンプル プロジェクトを開く

まず、サンプル プロジェクトをダウンロードします。

  1. Web ブラウザーで https://aka.ms/learn-da-api-ts-repairs に移動します。 サンプル プロジェクトを含む ZIP ファイルをダウンロードするように求めるメッセージが表示されます。
  2. コンピューターに ZIP ファイルを保存します。
  3. ZIP ファイルの内容を抽出します。
  4. Visual Studio Code でフォルダーを開きます。

サンプル プロジェクトは、宣言型エージェント、API プラグイン、およびMicrosoft Entra IDで保護された API を含む Microsoft 365 Agents Toolkit プロジェクトです。 API はAzure Functionsで実行されており、Azure Functions組み込みの認証と承認機能 (Easy Auth とも呼ばれます) を使用してセキュリティを実装します。

OAuth2 承認構成を調べる

続行する前に、サンプル プロジェクトの OAuth2 承認構成を調べます。

API 定義を調べる

まず、プロジェクトに含まれる API 定義のセキュリティ構成を確認します。

Visual Studio Code で次の手順を実行します。

  1. appPackage/apiSpecificationFile/repair.yml ファイルを開きます。

  2. components.securitySchemes セクションで、oAuth2AuthCode プロパティに注目してください。

    components:
      securitySchemes:
        oAuth2AuthCode:
          type: oauth2
          description: OAuth configuration for the repair service
          flows:
            authorizationCode:
              authorizationUrl: https://login.microsoftonline.com/${{AAD_APP_TENANT_ID}}/oauth2/v2.0/authorize
              tokenUrl: https://login.microsoftonline.com/${{AAD_APP_TENANT_ID}}/oauth2/v2.0/token
              scopes:
                api://${{AAD_APP_CLIENT_ID}}/repairs_read: Read repair records 
    

    プロパティは OAuth2 セキュリティ スキームを定義し、アクセス トークンを取得するために呼び出す URL と API が使用するスコープに関する情報を含みます。

    重要

    スコープは、アプリケーション ID URI (api://...) で完全修飾されていることに注意してください。Microsoft Entraを使用する場合は、カスタム スコープを完全に修飾する必要があります。 Microsoft Entraに修飾されていないスコープが表示されると、それが Microsoft Graph に属していると見なされ、承認フロー エラーが発生します。

  3. paths./repairs.get.security プロパティを見つけます。 クライアントが操作を実行する必要がある oAuth2AuthCode セキュリティ スキームとスコープを参照していることに注意してください。

    [...]
    paths:
      /repairs:
        get:
          operationId: listRepairs
          [...]
          security:
            - oAuth2AuthCode:
              - api://${{AAD_APP_CLIENT_ID}}/repairs_read
    [...]
    

    重要

    API 仕様で必要なスコープを一覧表示することは、純粋に情報です。 API を実装するときは、トークンを検証し、必要なスコープが含まれていることを確認する必要があります。

API の実装を調べる

次に、API の実装を見てみましょう。

Visual Studio Code で次の手順を実行します。

  1. src/functions/repairs.ts ファイルを開きます。

  2. repairs ハンドラー関数で、要求に必要なスコープを持つアクセス トークンが含まれているかどうかを確認する次の行を見つけます。

    if (!hasRequiredScopes(req, 'repairs_read')) {
      return {
        status: 403,
        body: "Insufficient permissions",
      };
    }
    
  3. hasRequiredScopes 関数は、repairs.ts ファイルにさらに実装されます。

    function hasRequiredScopes(req: HttpRequest, requiredScopes: string[] | string): boolean {
      if (typeof requiredScopes === 'string') {
        requiredScopes = [requiredScopes];
      }
    
      const token = req.headers.get("Authorization")?.split(" ");
      if (!token || token[0] !== "Bearer") {
        return false;
      }
    
      try {
        const decodedToken = jwtDecode<JwtPayload & { scp?: string }>(token[1]);
        const scopes = decodedToken.scp?.split(" ") ?? [];
        return requiredScopes.every(scope => scopes.includes(scope));
      }
      catch (error) {
        return false;
      }
    }
    

    関数は、まず、承認要求ヘッダーからベアラー トークンを抽出します。 次に、 jwt-decode パッケージを使用してトークンをデコードし、 scp 要求からスコープの一覧を取得します。 最後に、 scp 要求に必要なすべてのスコープが含まれているかどうかを確認します。

    関数でアクセス トークンが検証されていないことに注意してください。 代わりに、アクセス トークンに必要なスコープが含まれているかどうかを確認するだけです。 このテンプレートでは、API はAzure Functionsで実行されており、アクセス トークンの検証を担当する Easy Auth を使用してセキュリティを実装します。 要求に有効なアクセス トークンが含まれていない場合、Azure Functions ランタイムはコードに到達する前に拒否します。 Easy Auth はトークンを検証しますが、必要なスコープはチェックしません。これは自分で行う必要があります。

コンテナー タスクの構成を調べる

このプロジェクトでは、Microsoft 365 Agents Toolkit を使用して OAuth 情報をコンテナーに追加します。 Microsoft 365 Agents Toolkit は、プロジェクトの構成で特別なタスクを使用して、コンテナーに OAuth 情報を登録します。

Visual Studio Code で次の手順を実行します。

  1. ./teampsapp.local.yml ファイルを開きます。

  2. [ プロビジョニング ] セクションで、 oauth/register タスクを見つけます。

    - uses: oauth/register
      with:
        name: oAuth2AuthCode
        flow: authorizationCode
        appId: ${{TEAMS_APP_ID}}
        clientId: ${{AAD_APP_CLIENT_ID}}
        clientSecret: ${{SECRET_AAD_APP_CLIENT_SECRET}}
        isPKCEEnabled: true
        # Path to OpenAPI description document
        apiSpecPath: ./appPackage/apiSpecificationFile/repair.yml
      writeToEnvironmentFile:
        configurationId: OAUTH2AUTHCODE_CONFIGURATION_ID
    

    タスクは、env/.env.local および env/.env.local.user ファイルに格納されているTEAMS_APP_IDAAD_APP_CLIENT_ID、SECRET_AAD_APP_CLIENT_SECRET プロジェクト変数の値を受け取り、コンテナーに登録します。 また、追加のセキュリティ対策として Proof Key for Code Exchange (PKCE) も有効になります。 次に、コンテナーエントリ ID を受け取り、 環境ファイル env/.env.local に書き込みます。 このタスクの結果は、 OAUTH2AUTHCODE_CONFIGURATION_ID という名前の環境変数です。 Microsoft 365 Agents Toolkit は、この変数の値を、プラグイン定義を含む appPackages/ai-plugin.json ファイルに書き込みます。 実行時に、API プラグインを読み込む宣言型エージェントは、この ID を使用してコンテナーから OAuth 情報を取得し、開始フローと認証フローを使用してアクセス トークンを取得します。

    重要

    oauth/register タスクは、コンテナーに OAuth 情報がまだ存在しない場合にのみ登録します。 情報が既に存在する場合、Microsoft 365 Agents Toolkit はこのタスクの実行をスキップします。

  3. 次に、 oauth/update タスクを見つけます。

    - uses: oauth/update
      with:
        name: oAuth2AuthCode
        appId: ${{TEAMS_APP_ID}}
        apiSpecPath: ./appPackage/apiSpecificationFile/repair.yml
        configurationId: ${{OAUTH2AUTHCODE_CONFIGURATION_ID}}
        isPKCEEnabled: true
    

    このタスクでは、コンテナー内の OAuth 情報がプロジェクトと同期されます。 プロジェクトが正常に動作するためには、それが必要です。 重要なプロパティの 1 つは、API プラグインを使用できる URL です。 プロジェクトを開始するたびに、Microsoft 365 Agents Toolkit によって新しい URL の開発トンネルが開きます。 コンテナー内の OAuth 情報は、Copilot が API に到達できるように、この URL を参照する必要があります。

認証と承認の構成を確認する

次に、Azure Functionsの認証と承認の設定について説明します。 この演習の API では、Azure Functionsの組み込みの認証と承認の機能を使用します。 Microsoft 365 Agents Toolkit は、Azure へのAzure Functionsプロビジョニング中にこれらの機能を構成します。

Visual Studio Code で次の手順を実行します。

  1. infra/azure.bicep ファイルを開きます。

  2. authSettings リソースを見つけます。

    resource authSettings 'Microsoft.Web/sites/config@2021-02-01' = {
      parent: functionApp
      name: 'authsettingsV2'
      properties: {
        globalValidation: {
          requireAuthentication: true
          unauthenticatedClientAction: 'Return401'
        }
        identityProviders: {
          azureActiveDirectory: {
            enabled: true
            registration: {
              openIdIssuer: oauthAuthority
              clientId: aadAppClientId
            }
            validation: {
              allowedAudiences: [
                aadAppClientId
                aadApplicationIdUri
              ]
            }
          }
        }
      }
    }
    

    このリソースにより、Azure Functions アプリの組み込みの認証と承認機能が有効になります。 まず、 globalValidation セクションで、アプリが認証された要求のみを許可することを定義します。 アプリが認証されていない要求を受け取った場合、401 HTTP エラーで拒否されます。 次に、identityProviders セクションで、構成では、Microsoft Entra ID (以前は Azure Active Directory と呼ばれる) を使用して要求を承認することを定義します。 API のセキュリティ保護に使用するアプリ登録Microsoft Entra、API の呼び出しを許可する対象ユーザーを指定します。

Microsoft Entra アプリケーションの登録を確認する

調査する最後の部分は、プロジェクトが API のセキュリティ保護に使用するアプリケーション登録Microsoft Entraです。 OAuth を使用する場合は、アプリケーションを使用してリソースへのアクセスをセキュリティで保護します。 アプリケーションは通常、クライアント シークレットや証明書などのアクセス トークンを取得するために必要な資格情報を定義します。 また、API を呼び出すときにクライアントが要求できるさまざまなアクセス許可 (スコープとも呼ばれます) も指定します。 Microsoft Entraアプリケーション登録は、Microsoft クラウド内のアプリケーションを表し、OAuth 承認フローで使用するアプリケーションを定義します。

Visual Studio Code で次の手順を実行します。

  1. ./aad.manifest.json ファイルを開きます。

  2. oauth2Permissions プロパティを見つけます。

    "oauth2Permissions": [
      {
        "adminConsentDescription": "Allows Copilot to read repair records on your behalf.",
        "adminConsentDisplayName": "Read repairs",
        "id": "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}",
        "isEnabled": true,
        "type": "User",
        "userConsentDescription": "Allows Copilot to read repair records.",
        "userConsentDisplayName": "Read repairs",
        "value": "repairs_read"
      }
    ],
    

    プロパティは、repairs API から修復を読み取るアクセス許可をクライアントに付与する repairs_read という名前のカスタム スコープを定義します。

  3. identifierUris プロパティを見つけます。

    "identifierUris": [
      "api://${{AAD_APP_CLIENT_ID}}"
    ]
    

    identifierUris プロパティは、スコープを完全に修飾するために使用される識別子を定義します。

Microsoft 365 Copilotで API プラグインを使用して宣言型エージェントをテストする

最後の手順では、Microsoft 365 Copilotで API プラグインを使用して宣言型エージェントをテストします。

Visual Studio Code で次の手順を実行します。

  1. アクティビティ バーで、 Microsoft 365 Agents Toolkit 拡張機能をアクティブにします。

  2. Microsoft 365 Agents Toolkit 拡張機能パネルの [アカウント] セクションで、Copilot が有効になっている Microsoft 365 テナントにサインインしていることを確認します。

    Microsoft 365 への接続の状態を示す Microsoft 365 エージェント ツールキットのスクリーンショット。

  3. アクティビティ バーで、[ 実行] ビューと [デバッグ ] ビューに切り替えます。

  4. 構成の一覧 から[Copilot (Edge)] で [デバッグ ] を選択し、再生ボタンを押してデバッグを開始します。

    Visual Studio Code のデバッグ オプションのスクリーンショット。

    Visual Studio Code では、Microsoft 365 Copilotを使用して新しい Web ブラウザーが開きます。 メッセージが表示されたら、Microsoft 365 アカウントを使用してサインインします。

Web ブラウザーで次の手順を実行します。

  1. サイド パネルで、 da-repairs-oauthlocal エージェントを 選択します。

    Microsoft 365 Copilotに表示されるカスタム エージェントのスクリーンショット。

  2. プロンプト テキスト ボックスに「 Show repair records assigned to Karin Blair 」と入力し、プロンプトを送信します。

    ヒント

    プロンプトを入力する代わりに、会話スターターから選択できます。

    カスタム宣言型エージェントで開始された会話のスクリーンショット。

  3. [常に許可] ボタンを使用して API プラグインにデータを送信することを確認します。

    API へのデータの送信を許可するプロンプトのスクリーンショット。

  4. メッセージが表示されたら、API にサインインして、Microsoft 365 テナントへのサインインに使用するアカウントと同じアカウントを引き続き使用するには、[ da-repairs-oauthlocal にサインイン] を選択します。

    API をセキュリティで保護するアプリにサインインするためのプロンプトのスクリーンショット。

  5. エージェントが応答するまで待ちます。

    ユーザーのプロンプトに対する宣言型エージェントの応答のスクリーンショット。

API はローカル コンピューターで実行されているため、匿名でアクセスできますが、Microsoft 365 Copilotは API 仕様で指定されているように認証された API を呼び出しています。修復関数にブレークポイントを設定し、宣言型エージェントで別のプロンプトを送信することで、要求にアクセス トークンが含まれていることを確認できます。 コードがブレークポイントに到達したら、req.headers コレクションを展開し、JSON Web トークン (JWT) を含む承認ヘッダーを探します。

ブレークポイントと、受信要求の承認ヘッダーを示すデバッグ パネルを含む Visual Studio Code のスクリーンショット。

テストが完了したら、Visual Studio Code でデバッグ セッションを停止します。