Azure AD B2C: Call a web API from a .NET web app

By using Azure Active Directory (Azure AD) B2C, you can add powerful self-service identity management features to your web apps and web APIs in a few short steps. This article will discuss how to create a .NET Model-View-Controller (MVC) "to-do list" web app that calls a web API by using bearer tokens

This article does not cover how to implement sign-in, sign-up and profile management with Azure AD B2C. It focuses on calling web APIs after the user is already authenticated. If you haven't already, you should start with the .NET web app getting started tutorial to learn about the basics of Azure AD B2C.

Get an Azure AD B2C directory

Before you can use Azure AD B2C, you must create a directory, or tenant. A directory is a container for all your users, apps, groups, and more. If you don't have one already, create a B2C directory before you continue in this guide.

Create an application

Next, you need to create an app in your B2C directory. This gives Azure AD information that it needs to securely communicate with your app. In this case, both the web app and web API will be represented by a single Application ID, because they comprise one logical app. To create an app, follow these instructions. Be sure to:

  • Include a web app/web API in the application.
  • Enter https://localhost:44316/ as a Reply URL. It is the default URL for this code sample.
  • Copy the Application ID that is assigned to your app. You will also need this later.
Important

You cannot use applications registered in the Applications tab on the classic Azure Management Portal for this.

Create your policies

In Azure AD B2C, every user experience is defined by a policy. This web app contains three identity experiences: sign up, sign in, and edit profile. You need to create one policy of each type, as described in the policy reference article. When you create the three policies, be sure to:

  • Choose the Display name and other sign-up attributes in your sign-up policy.
  • Choose the Display name and Object ID application claims in every policy. You can choose other claims as well.
  • Copy the Name of each policy after you create it. It should have the prefix b2c_1_. You'll need those policy names later.
Note

In Azure AD B2C, your policy's name will be prefixed with b2c_1_, like b2c_1_sign_up. You are free to use your policies across all of your apps, both client and server. If you've previously created policies in another B2C walk-through, there is no need to do so again. You may reuse the policies you've previously created in the portal if they match the requirements of the application.

After you have created your three policies, you're ready to build your app.

Note that this article does not cover how to use the policies that you just created. To learn about how policies work in Azure AD B2C, start with the .NET web app getting started tutorial.

Download the code

The code for this tutorial is maintained on GitHub. To build the sample as you go, you can download the skeleton project as a .zip file. You can also clone the skeleton:

git clone --branch skeleton https://github.com/AzureADQuickStarts/B2C-WebApp-WebAPI-OpenIDConnect-DotNet.git

The completed app is also available as a .zip file or on the complete branch of the same repository.

After you download the sample code, open the Visual Studio .sln file to get started.

Configure the task web app

To get TaskWebApp to communicate with Azure AD B2C, you need to provide a few common parameters. In the TaskWebApp project, open the web.config file in the root of the project and replace the values in the <appSettings> section. You can leave the AadInstance, RedirectUri, and TaskServiceUrl values as they are.

  <appSettings>

    ...

    <add key="ida:ClientId" value="90c0fe63-bcf2-44d5-8fb7-b8bbc0b29dc6" />
    <add key="ida:AadInstance" value="https://login.microsoftonline.com/{0}/v2.0/.well-known/openid-configuration?p={1}" />
    <add key="ida:RedirectUri" value="https://localhost:44316/" />
    <add key="ida:SignUpPolicyId" value="b2c_1_sign_up" />
    <add key="ida:SignInPolicyId" value="b2c_1_sign_in" />
    <add key="ida:UserProfilePolicyId" value="b2c_1_edit_profile" />
    <add key="api:TaskServiceUrl" value="https://aadb2cplayground.azurewebsites.net" />
  </appSettings>
Note

Your B2C tenant's name is the domain that you entered during tenant creation, and is displayed on the directory blade in the Azure portal. It usually ends with the suffix .onmicrosoft.com, for instance, contosob2c.onmicrosoft.com.

Get access tokens and call the task API

This section will discuss how to use the token received during sign-in with Azure AD B2C in order to access a web API that is also secured with Azure AD B2C.

This article does not cover the details of how to secure the API. To learn how a web API securely authenticates requests by using Azure AD B2C, check out the web API getting started article.

Save the sign in token

First, authenticate the user (using any one of your policies) and receive a sign-in token from Azure AD B2C. If you're not sure how to execute policies, go back and try the .NET web app getting started tutorial to learn about the basics of Azure AD B2C.

Open the file App_Start\Startup.Auth.cs. There is one important change you must make to the OpenIdConnectAuthenticationOptions - you must set SaveSignInToken = true.

// App_Start\Startup.Auth.cs

return new OpenIdConnectAuthenticationOptions
{
    // For each policy, give OWIN the policy-specific metadata address, and
    // set the authentication type to the id of the policy
    MetadataAddress = String.Format(aadInstance, tenant, policy),
    AuthenticationType = policy,

    // These are standard OpenID Connect parameters, with values pulled from web.config
    ClientId = clientId,
    RedirectUri = redirectUri,
    PostLogoutRedirectUri = redirectUri,
    Notifications = new OpenIdConnectAuthenticationNotifications
    {
        AuthenticationFailed = OnAuthenticationFailed,
    },
    Scope = "openid",
    ResponseType = "id_token",

    TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "name",

        // Add this line to reserve the sign in token for later use
        SaveSigninToken = true,
    },
};

Get a token in the controllers

The TasksController is responsible for communicating with the web API, sending HTTP requests to the API to read, create, and delete tasks. Becuase the API is secured by Azure AD B2C, you need to first retrieve the token you saved in the above step.

// Controllers\TasksController.cs

public async Task<ActionResult> Index()
{
    try {

        var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;

    ...
}

The BootstrapContext contains the sign in token that you acquired by executing one of your B2C policies.

Read tasks from the web API

When you have a token, you can attach it to the HTTP GET request in the Authorization header to securely call TaskService:

// Controllers\TasksController.cs

public async Task<ActionResult> Index()
{
    try {

        ...

        HttpClient client = new HttpClient();
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, serviceUrl + "/api/tasks");

        // Add the token acquired from ADAL to the request headers
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", bootstrapContext.Token);
        HttpResponseMessage response = await client.SendAsync(request);

        if (response.IsSuccessStatusCode)
        {
            String responseString = await response.Content.ReadAsStringAsync();
            JArray tasks = JArray.Parse(responseString);
            ViewBag.Tasks = tasks;
            return View();
        }
        else
        {
            // If the call failed with access denied, show the user an error indicating they might need to sign-in again.
            if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
            {
                return new RedirectResult("/Error?message=Error: " + response.ReasonPhrase + " You might need to sign in again.");
            }
        }

        return new RedirectResult("/Error?message=An Error Occurred Reading To Do List: " + response.StatusCode);
    }
    catch (Exception ex)
    {
        return new RedirectResult("/Error?message=An Error Occurred Reading To Do List: " + ex.Message);
    }
}

Create and delete tasks on the web API

Follow the same pattern when you send POST and DELETE requests to the web API, using the BootstrapContext to retrieve the sign in token. We implemented the create action for you. You can try finishing the delete action in TasksController.cs.

Run the sample app

Finally, build and run the app. Sign up and sign in, and create tasks for the signed-in user. Sign out and sign in as a different user. Create tasks for that user. Notice how the tasks are stored per-user on the API, because the API extracts the user's identity from the token it receives.

For reference, the completed sample is provided as a .zip file. You can also clone it from GitHub:

git clone --branch complete https://github.com/AzureADQuickStarts/B2C-WebApp-WebAPI-OpenIDConnect-DotNet.git