AcquireTokenForUser in ASP.NET Core Web app

46 Views Asked by At

I have a AspNetCore app in net6.0. The user is asked to login against Azure Ad (Entra).

After this is done, the web app needs to make a call to an API. The endpoint it hits has a scope requirement. This is a scope the web app registration has permission for in Azure.

How do I get a hold of a token containing that scope, so I can use it to authorize in the API? I've looked at _tokenAcquisition.AcquireTokenForUser, but even if I have all AzureAd configuration in pla, including a client secret, it says no account or login hint was passed to AcquireTokenSilent.

Reading the documentation confuses me, and it's hard to find a concrete example of what I'm after. I've tried different solutions in code, but none seem to work.

Any help appreciated, and let me know if more info is needed, thanks!

1

There are 1 best solutions below

4
Tiny Wang On BEST ANSWER

According to the error message, we can only say that you didn't sign in successfully so that the _tokenAcquisition failed to work. Since you didn't share how you compose your code, pls allow me to share my steps.

Firstly, I created a new .net 8 mvc application, when creating the app, I choose "Microsoft Identity Platform" as the authentication type. Then I need to modify the appsettings.json, Program.cs and HomeController.

"AzureAd": {
  "Instance": "https://login.microsoftonline.com/",
  "ClientId": "aad_client_id",
  "ClientSecret": "client_secret",
  "Domain": "tenant_id",
  "TenantId": "tenant_id",
  "CallbackPath": "/signin-oidc"
},

In Program.cs, add toke acquisition service, and http service to send http request.

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi()
    .AddInMemoryTokenCaches();

builder.Services.AddHttpClient();

Then inject related service to generate access token and send http request.

[Authorize]
public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly ITokenAcquisition _tokenAcquisition;
    private readonly IHttpClientFactory _httpClientFactory;

    public HomeController(ITokenAcquisition tokenAcquisition, ILogger<HomeController> logger, IHttpClientFactory httpClientFactory)
    {
        _tokenAcquisition = tokenAcquisition;
        _logger = logger;
        _httpClientFactory = httpClientFactory;
    }

    public async Task<IActionResult> IndexAsync()
    {
        var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new string[] { "api://client_id_exposing_API/Tiny.Read" });

        var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://localhost:7076/home/getData")
        {
            Headers =
            {
                { HeaderNames.Authorization, "Bearer "+ accessToken}
            }
        };

        var httpClient = _httpClientFactory.CreateClient();
        var response = await httpClient.SendAsync(httpRequestMessage);
        if (response.StatusCode == HttpStatusCode.OK)
        {
            var result = await response.Content.ReadAsStringAsync();
        }
        return View();
    }

    [AllowAnonymous]
    public string getData() {
        return "success";
    }
}

Just like you see, after I sign in the app and hit the action method, I can generate access token successfully which containing correct scope I set in my method.

enter image description here

Nuget packages I used are generated by VS 2022 template:

<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" NoWarn="NU1605" />
  <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.0" NoWarn="NU1605" />
  <PackageReference Include="Microsoft.Identity.Web" Version="2.15.2" />
  <PackageReference Include="Microsoft.Identity.Web.UI" Version="2.15.2" />
  <PackageReference Include="Microsoft.Identity.Web.DownstreamApi" Version="2.15.2" />
</ItemGroup>