ネストされたアプリの認証

注:

入れ子になったアプリ認証 (NAA) は、タブなどのシングルページ アプリケーション (SPA) でのみサポートされます。

NAA は、Teams、Outlook、Microsoft 365 などのホスト環境に埋め込まれている SPA 用の新しい認証プロトコルです。 認証プロセスを簡略化し、サポートされているホスト アプリ内にネストされたアプリ間でシングル サインオン (SSO) を容易にします。 NAA モデルでは、ネストされたアプリの複数のアプリ ID を含むホスト アプリのプライマリ ID がサポートされます。 Microsoft では、Teams タブ、個人用アプリ、Office アドインでこのモデルを利用します。

NAA モデルには、On-Behalf-Of (OBO) フローに比べていくつかの利点があります。

  • NAA では、MSAL.js ライブラリのみを使用する必要があります。 Teams JavaScript クライアント ライブラリ (TeamsJS) の getAuthToken 関数を使用する必要はありません。

  • クライアント コードからのアクセス トークンを使用して SPA として Microsoft Graph などのサービスを呼び出すことができます。 ミドル層サーバーは必要ありません。

  • スコープ (アクセス許可) には、増分同意と動的同意を使用できます。

  • Teams や Microsoft 365 などのホストがエンドポイントを呼び出すために事前に承認する必要はありません。

    次の表は、Teams Microsoft Entra SSO と NAA の違いを示しています。

    開発に必要な手順 従来の Teams Entra SSO NAA
    リダイレクト URI の公開 必須 必須
    Microsoft Entra ID に API を登録する 必須
    Microsoft Entra ID でカスタム スコープを定義する 必須
    Teams クライアント アプリを承認する 必須
    アプリ マニフェスト (以前は Teams アプリ マニフェストと呼ばれていました) を改訂します 必須 推奨*
    TeamsJS SDK を使用してアクセス トークンを取得する 必須
    追加のアクセス許可についてユーザーの同意を求める 必須
    サーバーで OBO 交換を実行する 必須
  • IT 管理者は、アプリをブロックしたり、Microsoft Entra ID のアプリの特定のアクセス許可のみに同意したりできます。 これを回避するには、管理者が Teams 管理センターでアクセス許可を承認できるように、アプリ マニフェストにアプリ ID と既定のリソースを含める必要があります。

NAA の使用事例

シナリオ 説明
SSO (およびその他のアクセス許可) への同意 Contoso デザイン チームの新しいメンバーである Tom は、Teams 会議で Contoso アプリを使用してホワイトボードで共同作業を行う必要があります。 初めて使用するときに、アバター (User.Read) のプロファイルの読み取りを含むアクセス許可を付与するように Tom に求めるダイアログが表示されます。 同意すると、Tom は今後の会議でデバイス間で Contoso をシームレスに使用できます。
再認証または条件付きアクセス ステップアップ認証 トムはオーストラリアから働いていると、Teams 内の Contoso にアクセスするために多要素認証 (MFA) を必要とする条件付きアクセス トリガーに遭遇します。 ダイアログは、さらに検証が必要であることを Tom に通知し、MFA プロセスを通して Contoso を引き続き使用するように導きます。
エラー アカウント情報の取得中に問題があるため、Contoso でサインイン エラーが発生する。 トムには、再認証を求める再試行ボタンが表示されます。 ただし、システム管理者が Contoso へのアクセスを制限していることがわかります。

NAA の構成

入れ子になった認証を構成するには、次の手順を実行します。

  1. SPA を登録する
  2. 信頼されたブローカーを追加する
  3. パブリック クライアント アプリを初期化する
  4. 最初のトークンを取得する
  5. API を呼び出す

SPA を登録する

アドインの Microsoft Entra ID アプリ登録を Azure portal で作成する必要があります。 アプリの登録には、名前、サポートされているアカウントの種類、SPA リダイレクトが必要です。 アプリの登録後、Azure portal によって Microsoft Entra アプリの登録 ID が生成されます。 アドインで NAA および SSO 以外の追加のアプリ登録が必要な場合は、「シングルページ アプリケーションの登録」を参照してください。

信頼されたブローカーを追加する

入れ子になったアプリ認証を構成するには、アプリでアプリのリダイレクト URI をアクティブに構成する必要があります。 リダイレクト URI は、サポートされているホストによってアプリを仲介できることを Microsoft ID プラットフォームに示します。 アプリのリダイレクト URI は、 シングルページ アプリケーション 型で、次のスキームに準拠している必要があります。

brk-multihub://<your_domain>

ここで

  • brk-multihub Teams、Outlook、Microsoft365.com など、実行するように構成されている Microsoft 365 のサポート対象ホストによって認証を仲介できます。
  • <your_domain> は、アプリがホストされる完全修飾ドメイン名です。 たとえば、 brk-multihub://contoso.com です。

ドメインには配信元のみを含め、そのサブパスは含めないでください。 例:

✔️ brk-multihub://myapp.teams.microsoft.com
❌ brk-multihub://myapp.teams.microsoft.com/go

Teams アプリを Outlook と Microsoft365.com で実行するようにアップグレードする方法の詳細については、「 Microsoft 365 全体に Teams アプリを拡張する」を参照してください。

パブリック クライアント アプリを初期化する

注:

認証が成功するには、MSAL を初期化する前に TeamsJS を初期化します。

MSAL を初期化し、必要に応じてパブリック クライアント アプリのインスタンスを取得してアクセス トークンを取得します。

import {
  AccountInfo,
  IPublicClientApplication,
  createNestablePublicClientApplication,
} from "@azure/msal-browser";

const msalConfig = {
  auth: {
    clientId: "your_client_id",
    authority: "https://login.microsoftonline.com/{your_tenant_id}",
    supportsNestedAppAuth: true
  },
};

let pca: IPublicClientApplication;

export function initializePublicClient() {
  console.log("Starting initializePublicClient");
  return createNestablePublicClientApplication(msalConfig).then(
    (result) => {
      console.log("Client app created");
      pca = result;
      return pca;
    }
  );
}

最初のトークンを取得する

入れ子になったアプリ認証を通じて MSAL.js が取得したトークンは、Microsoft Entra アプリの登録 ID に対して発行されます。 MSAL.js は、ユーザー認証のためのトークン取得を処理します。 アクセス トークンをサイレントに取得しようとします。 それでも失敗した場合は、ユーザーに同意を求めるプロンプトが表示されます。 その後、トークンを使用して、Microsoft Graph API またはその他の Microsoft Entra ID で保護されたリソースを呼び出します。 OBO フローとは異なり、ホストがエンドポイントを呼び出すために事前承認する必要はありません。

トークンを取得するには、次の手順に従います。

  1. MSAL.js を使用して、アプリ ID のトークンを取得します。 詳細については、「 アクセス トークンの取得と使用」を参照してください。

  2. getActiveAccount API を使用して、publicClientApplicationを呼び出すアクティブなアカウントがあるかどうかを確認します。 アクティブなアカウントがない場合は、tenantID、homeAccountId、コンテキスト インターフェイスからのloginHintなどの追加のフィルター パラメーターを使用して、getAccount を使用してキャッシュからアカウントを取得してみてください。

    注:

    homeAccountId プロパティは、TeamsJS の userObjectId と同じです。

  3. publicClientApplication.acquireTokenSilent(accessTokenRequest) を呼び出して、ユーザーの操作なしでトークンを暗黙的に取得します。 accessTokenRequest アクセス トークンが要求されるスコープを指定します。 NAA は、段階的同意と動的な同意をサポートします。 コードがタスクを完了するために必要な最小限のスコープを常に要求してください。

  4. 使用可能なアカウントがない場合、MSAL.js は InteractionRequiredAuthErrorを返します。 publicClientApplication.acquireTokenPopup(accessTokenRequest) を呼び出して、ユーザーに対話型のダイアログを表示します。 acquireTokenSilent トークンの有効期限が切れた場合、またはユーザーが要求されたすべてのスコープに同意しなかった場合は、失敗する可能性があります。

    次のコード スニペットでは、トークンにアクセスする例を示します。

    
      // MSAL.js exposes several account APIs, logic to determine which account to use is the responsibility of the developer
      const account = publicClientApplication.getActiveAccount();
    
      const accessTokenRequest = {
      scopes: ["user.read"],
      account: account,
      };
    
      publicClientApplication
        .acquireTokenSilent(accessTokenRequest)
        .then(function (accessTokenResponse) {
          // Acquire token silent success
          let accessToken = accessTokenResponse.accessToken;
          // Call your API with token
          callApi(accessToken);
        })
        .catch(function (error) {
          //Acquire token silent failure, and send an interactive request
          if (error instanceof InteractionRequiredAuthError) {
            publicClientApplication
              .acquireTokenPopup(accessTokenRequest)
              .then(function (accessTokenResponse) {
                // Acquire token interactive success
                let accessToken = accessTokenResponse.accessToken;
                // Call your API with token
                callApi(accessToken);
              })
              .catch(function (error) {
                // Acquire token interactive failure
                console.log(error);
              });
          }
          console.log(error);
        });
    
    

API を呼び出す

トークンを受け取ったら、トークンを使用して API を呼び出します。 これにより、サーバーに対して認証された要求を行うために、API が有効なトークンで呼び出されるようになります。

次の例は、Microsoft Graph API に対して認証された要求を行い、Microsoft 365 データにアクセスする方法を示しています。


var headers = new Headers();
var bearer = "Bearer " + access_token;
headers.append("Authorization", bearer);
var options = {
    method: "GET",
    headers: headers
};

var graphEndpoint = "<https://graph.microsoft.com/v1.0/me>";

fetch(graphEndpoint, options)
    .then(function (response) {
        //do something with response
    });

入れ子になったアプリ認証 (NAA) のためのトークン プリフェッチ

パフォーマンスを向上させ、認証の待機時間を短縮するために、入れ子になったアプリ認証 (NAA) ではトークンのプリフェッチがサポートされています。 この機能により、ホストはアプリが起動する前に認証トークンを事前に取得できるため、保護されたリソースにすばやくアクセスできるようになります。

トークンのプリフェッチを有効にする方法

トークンのプリフェッチを有効にするには、Teams アプリ マニフェストをバージョン 1.22 以降に更新し、webApplicationInfo 内に nestedAppAuthInfo セクションを含めます。

{
 "webApplicationInfo": {
   "id": "33333ddd-0000-0000-0000-88888757bbbb",
   "resource": "api://app.com/botid-33333ddd-0000-0000-0000-88888757bbbb",
   "nestedAppAuthInfo": [
     {
       "redirectUri": "brk-multihub://app.com",
       "scopes": ["openid", "profile", "offline_access"],
       "claims": "{\"access_token\":{\"xms_cc\":{\"values\":[\"CP1\"]}}}"
     }
   ]
 }
}

重要

  • NAA トークン プリフェッチ要求ごとに、対応するnestedAppAuthInfo エントリのオプションの clientId フィールドに、エージェントまたはアプリのMicrosoft Entra ID登録クライアント ID を指定します。 指定された場合、この値はそのエントリのトークンをプリフェッチするために使用されます。 エントリに clientId が含まれていない場合、ホストはそのエントリの NAA トークン プリフェッチ要求のクライアント ID として webApplicationInfo.id を使用します。
  • webApplicationInfo.id clientId を指定しないエントリのフォールバック クライアント ID です。 すべてのエントリ レベルの clientId と一致する必要はありません。 アプリが NAA トークンのプリフェッチに webApplicationInfo.id のみを使用する場合、その値は実際の NAA トークン要求に使用されるアプリのMicrosoft Entra ID登録のクライアント ID と一致する必要があります。
  • webApplicationInfo.id の値とnestedAppAuthInfo内のすべてのフィールドは、アプリのランタイム NAA トークン要求で使用されるパラメーターと完全に一致する必要があります。 スコープ、リダイレクト URI、要求の違いなど、不一致があると、ホストはキャッシュからトークンを提供できなくなります。
  • プリフェッチされたトークンは、アプリの初回読み込み時にのみ使用するようになっており、短時間メモリに格納されます。 アプリが後でトークンの取得を試みた場合 (ユーザー操作への応答など)、プリフェッチされたトークンが使用できなくなる可能性があります。 このような場合、アプリは標準の認証フローを使用して新しいトークン要求を開始する必要があります。

メカニズム

トークン プリフェッチが有効になっている場合、ホスト環境は、アプリがレンダリングされる前に必要なトークンの取得とキャッシュを試みます。 これらのトークンはメモリに保存され、起動するとすぐにアプリで使用できるようになります。

この動作は、タブの読み込み中に getAuthToken API が自動的にトリガーされた従来の Teams SSO モデルのプリフェッチ機能に似ています。 入れ子になったアプリ認証 (NAA) では、この機能はマニフェスト構成によって導入され、バックエンド トークン交換を必要とせずにパフォーマンスが向上します。

NAAでのトークンプリフェッチの利点

  • アプリの起動中の認証の遅延を減らすことでパフォーマンスを向上させる
  • 入れ子になったアプリ全体で、サインインを繰り返すことなくシングル サインオン (SSO) を有効にする

注:

トークンのプリフェッチは現在、Microsoft Teams Web クライアントとデスクトップ クライアントでのみサポートされています。

ベスト プラクティス

  • 可能な場合は常にサイレント認証を使用する: MSAL.js は、ユーザーにプロンプトを表示せずにサイレント トークン要求を行うことによってトークンの更新を処理する acquireTokenSilent メソッドを提供します。 このメソッドはまず、ブラウザー ストレージ内の有効なキャッシュ トークンを検索します。 見つからない場合、ライブラリは Microsoft Entra ID に対してサイレント要求を行い、アクティブなユーザー セッション (Microsoft Entra ドメインのブラウザーで設定された Cookie によって決定される) がある場合、Microsoft Entra ID は新しいトークンを返します。 ライブラリは acquireTokenSilent メソッドを自動的に呼び出すことはありません。 API 呼び出しを行う前に、アプリで acquireTokenSilent を呼び出して有効なトークンを取得することをお勧めします。

    場合によっては、 acquireTokenSilent メソッドを使用してトークンを取得しようとすると失敗します。 たとえば、Microsoft Entra ID でのユーザー セッションの有効期限が切れたり、アプリ ユーザーによってパスワードが変更されたりすると、acquireTokenSilentは失敗します。 対話型トークン取得メソッド (acquireTokenPopup) を呼び出します。

  • フォールバックを用意する: NAA フローは、Microsoft エコシステム全体に互換性を提供します。 ただし、アプリが、NAA をサポートするように更新されていない下位レベルのクライアントまたはレガシ クライアントに表示される場合があります。 このような場合、アプリではシームレス SSO をサポートできないため、ユーザーと対話して認証ダイアログを開くために特別な API を呼び出す必要がある場合があります。 詳細については、「 タブ アプリの SSO を有効にする」を参照してください。

    注:

    Microsoft Entra 以外の ID プロバイダーを使用している場合は、NAA を使用しないでください。代わりにポップアップ認証を使用できます。

  • NAA のサポート: NAA は、すべてのホスト アプリ環境でサポートされているとは限りません。 現在のクライアントがこの機能をサポートしているかどうかを確認するには、指定された API を呼び出してその状態を判断できます。 戻り値 true は NAA のサポートを示し、 false はサポートされていないことを示します。

  • 複数の環境でアプリをテストする: アプリが Web ビューとブラウザーの両方の展開で動作することが予想される場合は、両方の展開環境でアプリをテストして、期待どおりに動作することを確認することをお勧めします。 ブラウザーで機能する特定の API は、Web ビュー内では動作しない場合があります。

コード サンプル

サンプルの名前 説明 .NET Node.js
ネストされたアプリの認証 このサンプルでは、Microsoft Teams タブ内の Microsoft Entra シングル サインオン (SSO) を示します。On-Behalf-Of (OBO) フローを利用して、ユーザーの代わりに Microsoft Graph API を呼び出します。 表示 表示

関連項目