モバイル アプリから Web API を呼び出す

アプリがユーザーをサインインさせ、トークンを受信すると、Microsoft Authentication Library (MSAL) では、ユーザー、ユーザーの環境、発行されたトークンに関する情報を公開します。 アプリではこれらの値が使用され、Web API を呼び出したり、ウェルカム メッセージをユーザーに表示したりすることができます。

この記事では、最初に MSAL の結果を確認します。 次に、AuthenticationResult または result からのアクセス トークンを使用して保護された Web API を呼び出す方法を説明します。

MSAL の結果

MSAL には次のような値があります。

  • AccessToken は、HTTP ベアラー要求で保護された Web API を呼び出します。
  • IdToken には、サインインしたユーザーに関する有用な情報が含まれています。 この情報には、ユーザー名、ホーム テナント、ストレージの一意識別子などが含まれます。
  • ExpiresOn はトークンの有効期限です。 MSAL は、アプリの自動更新を処理します。
  • TenantId は、ユーザーがサインインした場所のテナントの識別子です。 Microsoft Entra B2B のゲスト ユーザーの場合、この値によって、ユーザーがサインインしたテナントが識別されます。 この値は、ユーザーのホーム テナントを識別しません。
  • Scopes は、お使いのトークンで付与されたスコープを示します。 付与されたスコープは、要求したスコープのサブセットである場合があります。

また、MSAL では Account 値の抽象化も提供されます。 Account 値は、現在のユーザーのサインインしたアカウントを表します。

  • HomeAccountIdentifier は、ユーザーのホーム テナントの識別子を識別します。
  • UserName は、ユーザーの推奨ユーザー名です。 Azure AD B2C ユーザーの場合、この値は空の場合があります。
  • AccountIdentifier は、サインインしているユーザーを識別します。 ほとんどの場合、ユーザーが別のテナントのゲストでない限り、この値は HomeAccountIdentifier 値と同じです。

API を呼び出す

アクセス トークンがあれば、Web API を呼び出すことができます。 お使いのアプリではトークンを使って HTTP 要求が作成され、実行されます。

Android

        RequestQueue queue = Volley.newRequestQueue(this);
        JSONObject parameters = new JSONObject();

        try {
            parameters.put("key", "value");
        } catch (Exception e) {
            // Error when constructing.
        }
        JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, MSGRAPH_URL,
                parameters,new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                // Successfully called Graph. Process data and send to UI.
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                // Error.
            }
        }) {
            @Override
            public Map<String, String> getHeaders() throws AuthFailureError {
                Map<String, String> headers = new HashMap<>();

                // Put access token in HTTP request.
                headers.put("Authorization", "Bearer " + authResult.getAccessToken());
                return headers;
            }
        };

        request.setRetryPolicy(new DefaultRetryPolicy(
                3000,
                DefaultRetryPolicy.DEFAULT_MAX_RETRIES,
                DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        queue.add(request);

iOS および macOS 用の MSAL

トークンを取得するメソッドは MSALResult オブジェクトを返します。 MSALResultaccessToken プロパティを公開します。 accessToken を使用して、Web API を呼び出すことができます。 保護された Web API にアクセスするための呼び出しを行う前に、このプロパティを HTTP Authorization ヘッダーに追加してください。

NSMutableURLRequest *urlRequest = [NSMutableURLRequest new];
urlRequest.URL = [NSURL URLWithString:"https://contoso.api.com"];
urlRequest.HTTPMethod = @"GET";
urlRequest.allHTTPHeaderFields = @{ @"Authorization" : [NSString stringWithFormat:@"Bearer %@", accessToken] };

NSURLSessionDataTask *task =
[[NSURLSession sharedSession] dataTaskWithRequest:urlRequest
     completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {}];
[task resume];
let urlRequest = NSMutableURLRequest()
urlRequest.url = URL(string: "https://contoso.api.com")!
urlRequest.httpMethod = "GET"
urlRequest.allHTTPHeaderFields = [ "Authorization" : "Bearer \(accessToken)" ]

let task = URLSession.shared.dataTask(with: urlRequest as URLRequest) { (data: Data?, response: URLResponse?, error: Error?) in }
task.resume()

Xamarin

MSAL.NET の AuthenticationResult プロパティ

トークンを取得するメソッドでは、AuthenticationResult が返されます。 非同期メソッドでは、Task<AuthenticationResult> が返されます。

MSAL.NET では、AuthenticationResult は次を公開します。

  • Web API がリソースにアクセスするための AccessToken。 このパラメーターは、通常は base 64 でエンコードされた JWT の文字列です。 クライアントがアクセス トークン内を見ることはありません。 この形式が変わらないことは保証されておらず、リソース用に暗号化できます。 クライアント上のアクセス トークンのコンテンツに応じてコードを記述することは、エラーとクライアント ロジックの中断を起こす最大の原因の 1 つです。 詳細については、「アクセス トークン」を参照してください。
  • ユーザーの IdToken。 このパラメーターは、エンコードされた JWT です。 詳細については、ID トークンに関するページを参照してください。
  • トークンの有効期限の日時は、ExpiresOn から知ることができます。
  • TenantId には、ユーザーが存在するテナントが含まれています。 Microsoft Entra B2B のシナリオでのゲスト ユーザーの場合、テナント ID は一意のテナントではなく、ゲスト テナントです。 ユーザーにトークンが配信されるときに、AuthenticationResult にはこのユーザーに関する情報も含まれます。 アプリケーションのユーザーなしでトークンが要求される機密のクライアント フローの場合、このユーザー情報は null です。
  • トークンが発行された Scopes
  • ユーザーの一意の ID。

IAccount

MSAL.NET では、IAccount インターフェイスでアカウントの概念が定義されます。 この破壊的変更により、正しいセマンティクスが得られます。 同じユーザーは、異なる Microsoft Entra ディレクトリに複数のアカウントを持つことができます。 また、MSAL.NET では、ホーム アカウント情報が提供されるので、ゲスト シナリオについてはより詳細な情報が提供されます。 次の図は、IAccount インターフェイスの構造を示しています。

IAccount interface structure

AccountId クラスでは、次の表のプロパティで、特定のテナントのアカウントを識別します。

プロパティ 説明
TenantId GUID (アカウントが存在するテナントの ID) の文字列表現。
ObjectId GUID (テナント内でアカウントを所有するユーザーの ID) の文字列表現。
Identifier アカウントの一意識別子。 IdentifierObjectIdTenantId をコンマで区切って連結したものです。 base 64 ではエンコードされていません。

IAccount インターフェイスは 1 つのアカウントに関する情報を表します。 同じユーザーが異なるテナントに存在することができます。つまり、1 人のユーザーが複数のアカウントを持つことができます。 そのメンバーは、次の表のとおりです。

プロパティ 説明
Username UserPrincipalName (UPN) 形式の表示可能な値の文字列 (例: john.doe@contoso.com)。 null にすることができない HomeAccountId と HomeAccountId.Identifier とは異なり、この文字列は null にできます。 このプロパティは、MSAL.NET の以前のバージョンの IUserDisplayableId プロパティを置き換えます。
Environment このアカウントの ID プロバイダーを含む文字列 (例: login.microsoftonline.com)。 IdentityProvider には、クラウド環境に加えテナントに関する情報もありますが、それを除き、このプロパティは、IUserIdentityProvider プロパティと置き換えることができます。 ここでは値はホストのみです。
HomeAccountId ユーザーのホーム アカウントのアカウント ID。 このプロパティは、Microsoft Entra テナント全体でユーザーを一意に識別します。

トークンを使用して保護された API を呼び出す

MSAL によって resultAuthenticationResult が返された後、保護された Web API にアクセスする呼び出しを行う前に、これを HTTP Authorization ヘッダーに追加します。

httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

// Call the web API.
HttpResponseMessage response = await _httpClient.GetAsync(apiUri);
...
}

複数の API 要求を行う

同じ API を複数回呼び出す場合、または複数の API を呼び出す場合は、アプリを構築するときに、次の点を考慮してください。

  • 増分同意:Microsoft ID プラットフォームでは、すべて開始時にではなく、アクセス許可が必要なときに、アプリがユーザーの同意を得られるようにしています。 アプリが API を呼び出す準備ができたら、毎回、必要なスコープのみを要求します。

  • 条件付きアクセス: 複数の API 要求を行うときに、特定のシナリオでは、追加の条件付きアクセスの要件を満たさなければならない場合があります。 最初の要求に条件付きアクセス ポリシーが適用されておらず、アプリが条件付きアクセスを必要とする新しい API にサイレントでアクセスしようとする場合に、要件がこのように増加することがあります。 この問題に対処するため、必ずサイレント要求からのエラーをキャッチし、対話型の要求を行えるように準備します。 詳細については、条件付きアクセスについてのガイダンスを参照してください。

同じユーザーに対して複数の API を呼び出す場合、ユーザーのトークンを取得した後、続けて AcquireTokenSilent を呼び出してトークンを取得すれば、ユーザーに何度も資格情報の入力を求める必要がなくなります。

var result = await app.AcquireTokenXX("scopeApi1")
                      .ExecuteAsync();

result = await app.AcquireTokenSilent("scopeApi2")
                  .ExecuteAsync();

対話は、次の場合に必要です。

  • ユーザーが最初の API については同意したが、より多くのスコープについて同意する必要が生じた。 この場合は、増分同意を使用します。
  • 最初の API は多要素認証を必要としなかったが、次の API は多要素認証を必要とする。
var result = await app.AcquireTokenXX("scopeApi1")
                      .ExecuteAsync();

try
{
 result = await app.AcquireTokenSilent("scopeApi2")
                  .ExecuteAsync();
}
catch(MsalUiRequiredException ex)
{
 result = await app.AcquireTokenInteractive("scopeApi2")
                  .WithClaims(ex.Claims)
                  .ExecuteAsync();
}

次のステップ

このシナリオの次の記事「運用環境に移行する」に進みます。