Call a web API from a mobile app

After your app signs in a user and receives tokens, the Microsoft Authentication Library (MSAL) exposes information about the user, the user's environment, and the issued tokens. Your app can use these values to call a web API or display a welcome message to the user.

In this article, we'll first look at the MSAL result. Then we'll look at how to use an access token from AuthenticationResult or result to call a protected web API.

MSAL result

MSAL provides the following values:

  • AccessToken calls protected web APIs in an HTTP bearer request.
  • IdToken contains useful information about the signed-in user. This information includes the user's name, the home tenant, and a unique identifier for storage.
  • ExpiresOn is the expiration time of the token. MSAL handles an app's automatic refresh.
  • TenantId is the identifier of the tenant where the user signed in. For guest users in Microsoft Entra B2B, this value identifies the tenant where the user signed in. The value doesn't identify the user's home tenant.
  • Scopes indicates the scopes that were granted with your token. The granted scopes might be a subset of the scopes that you requested.

MSAL also provides an abstraction for an Account value. An Account value represents the current user's signed-in account:

  • HomeAccountIdentifier identifies the user's home tenant.
  • UserName is the user's preferred username. This value might be empty for Azure AD B2C users.
  • AccountIdentifier identifies the signed-in user. In most cases, this value is the same as the HomeAccountIdentifier value unless the user is a guest in another tenant.

Call an API

After you have the access token, you can call a web API. Your app will use the token to build an HTTP request and then run the request.

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);

MSAL for iOS and macOS

The methods to acquire tokens return an MSALResult object. MSALResult exposes an accessToken property. You can use accessToken to call a web API. Add this property to the HTTP authorization header before you call to access the protected web API.

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

AuthenticationResult properties in MSAL.NET

The methods to acquire tokens return AuthenticationResult. For async methods, Task<AuthenticationResult> returns.

In MSAL.NET, AuthenticationResult exposes:

  • AccessToken for the web API to access resources. This parameter is a string, usually a Base-64-encoded JWT. The client should never look inside the access token. The format isn't guaranteed to remain stable, and it can be encrypted for the resource. Writing code that depends on access token content on the client is one of the biggest sources of errors and client logic breaks. For more information, see Access tokens.
  • IdToken for the user. This parameter is an encoded JWT. For more information, see ID tokens.
  • ExpiresOn tells the date and time when the token expires.
  • TenantId contains the tenant in which the user was found. For guest users in Microsoft Entra B2B scenarios, the tenant ID is the guest tenant, not the unique tenant. When the token is delivered for a user, AuthenticationResult also contains information about this user. For confidential client flows where tokens are requested with no user for the application, this user information is null.
  • The Scopes for which the token was issued.
  • The unique ID for the user.

IAccount

MSAL.NET defines the notion of an account through the IAccount interface. This breaking change provides the right semantics. The same user can have several accounts, in different Microsoft Entra directories. Also, MSAL.NET provides better information in the case of guest scenarios because home account information is provided. The following diagram shows the structure of the IAccount interface.

IAccount interface structure

The AccountId class identifies an account in a specific tenant with the properties shown in the following table.

Property Description
TenantId A string representation for a GUID, which is the ID of the tenant where the account resides.
ObjectId A string representation for a GUID, which is the ID of the user who owns the account in the tenant.
Identifier Unique identifier for the account. Identifier is the concatenation of ObjectId and TenantId separated by a comma. They're not Base 64 encoded.

The IAccount interface represents information about a single account. The same user can be present in different tenants, which means that a user can have multiple accounts. Its members are shown in the following table.

Property Description
Username A string that contains the displayable value in UserPrincipalName (UPN) format, for example, john.doe@contoso.com. This string can be null, unlike HomeAccountId and HomeAccountId.Identifier, which won't be null. This property replaces the DisplayableId property of IUser in previous versions of MSAL.NET.
Environment A string that contains the identity provider for this account, for example, login.microsoftonline.com. This property replaces the IdentityProvider property of IUser, except that IdentityProvider also had information about the tenant, in addition to the cloud environment. Here, the value is only the host.
HomeAccountId The account ID of the home account for the user. This property uniquely identifies the user across Microsoft Entra tenants.

Use the token to call a protected API

After AuthenticationResult is returned by MSAL in result, add it to the HTTP authorization header before you make the call to access the protected web API.

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

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

Make several API requests

To call the same API several times, or call multiple APIs, then consider the following subjects when you build your app:

  • Incremental consent: The Microsoft identity platform allows apps to get user consent when permissions are required rather than all at the start. Each time your app is ready to call an API, it should request only the scopes that it needs.

  • Conditional Access: When you make several API requests, in certain scenarios you might have to meet additional conditional-access requirements. Requirements can increase in this way if the first request has no conditional-access policies and your app attempts to silently access a new API that requires Conditional Access. To handle this problem, be sure to catch errors from silent requests, and be prepared to make an interactive request. For more information, see Guidance for Conditional Access.

To call several APIs for the same user, after you acquire a token for the user, you can avoid repeatedly asking the user for credentials by subsequently calling AcquireTokenSilent to get a token:

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

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

Interaction is required when:

  • The user consented for the first API but now needs to consent for more scopes. In this case, you use incremental consent.
  • The first API doesn't require multi-factor authentication, but the next API does.
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();
}

Next steps

Move on to the next article in this scenario, Move to production.