Michele mpp Marostica
Michele mpp Marostica

Reputation: 2472

Azure AD: Call .net Core Web API from other .net Core Web API

I have a situation where there is a .net Core Web API that we use to manage some "machines". One of the exposed API is a simulation of the operation of such machines. The machines have different versions, each different versions have a different internal behavior but same interface.

We have, then, developed a series of different .net Core Web API to simulate each different versions of the machines.

I need therefore to call an API from an API, it's sound pretty straightforward as I'm doing it already with Microsoft Graph.

In startup.cs, I have:

public void ConfigureServices(IServiceCollection services)
{
    // To protect the API with Azure AD
    services
        .AddProtectedWebApi(Configuration);

    // To have ITokenAcquisition when calling the specific simulation API
    services
        .AddMicrosoftIdentityPlatformAuthentication(Configuration)
        .AddMsal(Configuration, new string[] { Configuration["SimulationAPIv411:Scope"] })
        .AddInMemoryTokenCaches();

I'm testing it with Postman with this flow in mind:

  1. I get a bearer token with Postman to access the generic API
  2. Postman call the SimulationDispatcherController in the generic API
  3. The SimulationDispatcherController calls the specific simulation API
  4. The result flow back to Postman

What I'm experiencing is:

  1. If I leave it like this, in postman I get as result a login page

    <!-- Copyright (C) Microsoft Corporation. All rights reserved. -->
    <!DOCTYPE html>
    <html dir="ltr" class="" lang="en">
    
    <head>
        <title>Sign in to your account</title>
    [...]
    
  2. If I remove the line .AddMicrosoftIdentityPlatformAuthentication(Configuration) then I can reach the SimulationDispatcherController but when it tries to call the other API I get the error:

    MSAL.NetCore.4.8.1.0.MsalUiRequiredException: 
    ErrorCode: user_null
    Microsoft.Identity.Client.MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.
    [...]
    

    I try to get the token with the ITokenAcquisition object, calling GetAccessTokenOnBehalfOfUserAsync(_Scopes); where the scope is the required one for the specific API.

Do you have any suggestion or link to documentation that explain better how to configure the MSAL in an API that is protected by Azure AD?

EDIT: As suggested in the answer, the only change required was:

.AddMsal(Configuration, new string[] { Configuration["SimulationAPIv411:Scope"] })

to

.AddProtectedApiCallsWebApis(Configuration)

Upvotes: 0

Views: 3760

Answers (2)

Jim Xu
Jim Xu

Reputation: 23141

If you want to call .net Core Web API from other .net Core Web API projected by Azure AD, you use the OAuth 2.0 On-Behalf-Of flow. The detailed steps are as below

  1. Sign-in the user in the client application
  2. Acquire a token to the Web API A and call it.
  3. The Web API then calls another downstream Web API B (I use Microsoft Graph for test).

Regarding how to configure it, please refer to the following steps:

Register the web api app

  1. Register APP
  2. Create Client secrets
  3. Configure permissions to access another web api. (I use Microsoft graph for test)
  4. Configure an application to expose web APIs(Add scope for the api)

Register the client app

  1. Register APP
  2. Create Client secrets
  3. Configure permissions to access web API

Configure known client applications for web API application

  1. In the Azure portal, navigate to your Web api app registration and click on the Manifest section.

  2. Find the property knownClientApplications and add the Client IDs of the client applications

Configure project

  1. Add the reference Microsoft.Identity.Web to your project

  2. add the following code in appsettings.json

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "<your tenant id>",
    "ClientId": "<app id of Web API A>",
    "ClientSecret": "<app secret of Web API A>"
  },
  1. add the following code in stratup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddProtectedWebApi(Configuration)
                   .AddProtectedApiCallsWebApis(Configuration)
                   .AddInMemoryTokenCaches();
  1. Controller
[Authorize]
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
              private readonly ITokenAcquisition _tokenAcquisition;
        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger, ITokenAcquisition tokenAcquisition)
        {
            _logger = logger;
            _tokenAcquisition = tokenAcquisition;
        }



        [HttpGet]
        public async Task<string> Get()
        {

            string[] scopes = { "user.read" }; // the scope of Web API B
            string accessToken = await _tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(scopes);
            // you use the accessToken to call the Web API B
            GraphServiceClient client = new GraphServiceClient(new DelegateAuthenticationProvider(
                    async (requestMessage) =>
                    {
                        requestMessage.Headers.Authorization =
                            new AuthenticationHeaderValue("Bearer", accessToken);
                    }));

            User user =await client.Me.Request().GetAsync();
            return user.UserPrincipalName;
        }

     }

Test in the Postman

  1. Get Tthe access token for the Web API A enter image description here enter image description here

  2. Call the Web API A then let Web API A call the Microsoft graph enter image description here

For more details, please refer to the document and the sample

Upvotes: 4

Nan Yu
Nan Yu

Reputation: 27578

That seems other specific simulation APIs are also protected by Azure AD , you can use OAuth 2.0 On-Behalf-Of flow which works in scenario where an application invokes a service/web API, which in turn needs to call another service/web API.

Here is code sample for using OBO flow in asp.net core web api with MSAL 2.3 and later.

Upvotes: 2

Related Questions