'Problem Using Microsoft.Identity.Web with Blazor Server App

I'm using Visual Studio V16.8.2 with the .Net 5 templates and I'm trying to create a Blazor Server app that will authenticate against Azure AD. I use the Blazor server template with work account authentication and single org options selected. The template setup the app registration and added the necessary AzureAD section in appsettings.json. When I build and run the app I get the consent screen and then the app asks me to choose the work account I want to use. From there it just constantly loops back to asking which work account I want to use.

If I create a different project using the MVC template instead of the Blazor Server one and select the same options, the app works fine with no looping back. Are there other steps either in code or in AAD configuration that are required to make the Blazor app work?

UPDATE: I just tried the Blazor Server on .Net Core 3.1 template and it seems to work fine. This template uses AspNetCore.Authentication instead of Identity.Web. It is just the Blazor template using Identity.Web that seems to create a problem.

UPDATE #2: The first time I used the Blazor Server 5.0 template I did not select the option to add authentication. I added it manually including app registrations, etc. I just re-did the exercise this time allowing the template to generate the app registrations. The difference seems to be that the template added 2 app registrations in AAD, one using the name of the project, and a second one that starts with the project name but adds an underscore followed by a numeric value to the end of the name. What is the purpose of the second app registration? It doesn't get put into the appsettings file.

UPDATE #3: I added an API and made it unprotected and the Blazor app was able to call it and the login via AAD worked fine. I then added the required code in startup.cs to support getting a token:

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

I retrieve the token and call the API with this code:

string[] scopes = new[] { _config["API:Scope"] };
var token = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response = await _httpClient.GetAsync($"{_config["API:BaseAddress"] }/WeatherForecast");

I also added the additional consent handler code to my Blazor page:

try
{
    forecasts = await ForecastService.GetForecastAsync();
}
catch (Exception ex)
{
    ConsentHandler.HandleException(ex);
}

Once this code is called I end up back in my authentication loop.



Solution 1:[1]

During the service configuration at:

.EnableTokenAcquisitionToCallDownstreamApi() 

you have to mention all the scopes you will refer to later on:

.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)

you can consider also to add additional configuration fro Graph (to get the User.Read permission)

.AddMicrosoftGraph(builder.Configuration.GetSection("MicrosoftGraph"))
.AddDownstreamWebApi("DownstreamApi",builder.Configuration.GetSection("DownstreamApi"))

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Ethan