Skip to content

Web APIs

Jean-Marc Prieur edited this page Jul 14, 2020 · 40 revisions

The Microsoft Identity Web library also enables web APIs to work with the Microsoft identity platform, enabling them to process access tokens for both work and school and Microsoft personal accounts, as well as B2C.

WebApiServiceCollectionExtensions

WebApiAuthentionBuilderExtensions

Protected web APIs - Startup.cs

Assuming you have a similar configuration in appsettings.json:

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "msidentitysamplestesting.onmicrosoft.com",
    "TenantId": "7f58f645-c190-4ce5-9de4-e2b7acd2a6ab",
    "ClientId": "a4c2469b-cf84-4145-8f5f-cb7bacf814bc"
  },
...
}

To enable the web API to accept tokens emitted by the Microsoft identity platform, replace this code in your web API's Startup.cs file:

using Microsoft.Identity.Web;

public class Startup
{
  ...
  public void ConfigureServices(IServiceCollection services)
  {
   ...
   services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
           .AddAzureAdBearer(options => Configuration.Bind("AzureAd", options));
   ...
  }
  ...
}

...with this code, using the AuthenticationBuilder:

using Microsoft.Identity.Web;

public class Startup
{
  ...
  public void ConfigureServices(IServiceCollection services)
  {
   ...
   services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
           .AddMicrosoftWebApi(Configuration);
   ...
  }
  ...
}

or with this code, using the services directly:

using Microsoft.Identity.Web;

public class Startup
{
  ...
  public void ConfigureServices(IServiceCollection services)
  {
   ...
      services.AddMicrosoftWebApiAuthentication(Configuration);
   ...
  }
  ...
}

This method enables your web API to be protected using the Microsoft identity platform. This includes validating the token in all scenarios (single- and multi-tenant applications) in the Azure public and national clouds.

See also:

What if the App ID URI of your application is not api://{ClientID}

The configuration file above assumes that the App ID URI for your application (the base segment of scopes exposed by your Web API) is api://{ClientID}. This is the default when your register your application with the application registration portal. However, you can override it. In that case, you'll want to explicitly set the Audience in your configuration to match the App ID URI for your Web API

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "msidentitysamplestesting.onmicrosoft.com",
    "TenantId": "7f58f645-c190-4ce5-9de4-e2b7acd2a6ab",
    "ClientId": "a4c2469b-cf84-4145-8f5f-cb7bacf814bc",
    "Audience": "api://myappreg.azurewebsites.net"
  },
...
}

Case of a B2C Web API

Assuming you have a similar configuration in appsettings.json:

{
  "AzureAdB2C": {
    "Instance": "https://fabrikamb2c.b2clogin.com",
    "ClientId": "90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6",
    "Domain": "fabrikamb2c.onmicrosoft.com",
    "SignedOutCallbackPath": "/signout/B2C_1_susi",
    "SignUpSignInPolicyId": "b2c_1_susi",
    "ResetPasswordPolicyId": "b2c_1_reset",
    "EditProfilePolicyId": "b2c_1_edit_profile" // Optional profile editing policy
  },
  // more here
}

To enable the web API to accept tokens emitted by Azure AD B2C, have the following code in your Web API:

using Microsoft.Identity.Web;

public class Startup
{
  ...
  public void ConfigureServices(IServiceCollection services)
  {
   ...
      services.AddMicrosoftdWebApiAuthentication(Configuration, "AzureAdB2C");
   ...
  }
  ...
}

Protected web APIs that call downstream APIs on behalf of a user - Startup.cs

Azure AD

If you want your web API to, moreover, call downstream web APIs, add the .AddMicrosoftWebApiCallsWebApi() line, and then choose a token cache implementation, for example .AddInMemoryTokenCaches():

using Microsoft.Identity.Web;

public class Startup
{
  ...
  public void ConfigureServices(IServiceCollection services)
  {
   ...
   services.AddMicrosoftWebApiAuthentication(Configuration)
           .AddMicrosoftWebApiCallsWebApi()
           .AddInMemoryTokenCaches();
   ...
  }
  ...
}

As with web apps, you can choose various token cache implementations.

If you're certain that your web API will need some specific scopes, you can optionally pass them as arguments to AddMicrosoftWebApiCallsWebApi.

Azure AD B2C

For Azure AD B2C, the code will be:

using Microsoft.Identity.Web;

public class Startup
{
  ...
  public void ConfigureServices(IServiceCollection services)
  {
   ...
   services.AddMicrosoftWebApiAuthentication(Configuration, "AzureAdB2C")
           .AddMicrosoftWebApiCallsWebApi()
           .AddInMemoryTokenCaches();
   ...
  }
  ...
}

Web API controller

To enable your web API to call downstream APIs:

  • Add (as in web apps) a parameter of type ITokenAcquisition to the constructor of your controller. The ITokenAcquisition service will be injected by dependency injection by ASP.NET Core.

  • In your controller actions, verify that the token contains the scopes expected by the action. To do so, call the VerifyUserHasAnyAcceptedScope extension method on the HttpContext.

  • Alternatively if your web API is called by a daemon app, use ValidateAppRoles()

    ScopesRequiredHttpContextExtensions
  • In your controller actions, call ITokenAcquisition.GetAccessTokenForUserAsync, passing the scopes for which to request a token.

  • Alternatively if you controller calls a downstream API on behalf of itself (instead of on behalf of the user), call ITokenAcquisition.GetAccessTokenForApplicationAsync, passing the scopes for which to request a token.

The following code snippet shows how to combine these steps:

[Authorize]
public class HomeController : Controller
{
  readonly ITokenAcquisition tokenAcquisition;

  static string[] scopeRequiredByAPI = new string[] { "access_as_user" };
  ...
  public async Task<IActionResult> Action()
  {
   HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByAPI);
   string[] scopes = new []{"user.read"};
   try
   {
      string accessToken = await _tokenAcquisition.GetAccessTokenOnBehalfOfUser(scopes);
      // call the downstream API with the bearer token in the Authorize header
    }
    catch (MsalUiRequiredException ex)
    {
      await _tokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeaderAsync(HttpContext, scopes, ex);
    }
   ...
  }

Handle conditional access

When your web API tries to get a token for the downstream API, the token acquisition service may throw a MsalUiRequiredException. The MsalUiRequiredException indicates that the user on the client calling the web API needs to perform additional actions, for example, multi-factor authentication.

Given that the web API isn't capable of performing such interaction itself, the exception needs to be passed to the client. To propagate the exception back to the client, catch the exception and call the ITokenAcquisition.ReplyForbiddenWithWwwAuthenticateHeaderAsync method.

Getting started with Microsoft Identity Web

Credentials

Token cache serialization

Web apps

Web APIs

Daemon scenario

Advanced topics

FAQ

News

Contribute

Other resources

Clone this wiki locally