0

I created a new blazor server project using dotnet new

dotnet new blazorserver --output "PlayingWithBlazor" --framework net6.0 --auth IndividualB2C --aad-b2c-instance "https://{mytenant}.b2clogin.com/" --domain "{mydomain}.onmicrosoft.com" --client-id "{myClientID}" --susi-policy-id "B2C_1_SignUp" --called-api-url "https://localhost:7042/api" --called-api-scopes "https://{mytennant}.onmicrosoft.com/a82e00f8-939d-47ab-b2f3-4e557020f729/access_as_user"

When I run the app using Visual Studio, I can log in using my AAD B2C user flow. However, when I click on "Call Web API" it throws an exception at await downstreamAPI.CallWebApiForUserAsync in CallWebAPI.razor

The @Code block for CallWebApi.razor that was autogenerated with the project looks like this:

@code { private HttpResponseMessage? response; private string? apiResult;

protected override async Task OnInitializedAsync()
{
    
    try
    {
     
        response = await downstreamAPI.CallWebApiForUserAsync(
                "DownstreamApi",
                options => options.RelativePath = "/Subscriber");

        if (response.StatusCode == System.Net.HttpStatusCode.OK)
        {
            apiResult = await response.Content.ReadAsStringAsync();
        }
        else
        {
            apiResult = "Failed to call the web API";
        }
    }
    catch (Exception ex)
    {
        ConsentHandler.HandleException(ex);
    }
}

Here is the Exception:

Microsoft.Identity.Web.MicrosoftIdentityWebChallengeUserException
  HResult=0x80131500
  Message=IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent. 
  Source=Microsoft.Identity.Web
  StackTrace:
   at Microsoft.Identity.Web.TokenAcquisition.<GetAuthenticationResultForUserAsync>d__16.MoveNext()
   at Microsoft.Identity.Web.DownstreamWebApi.<CallWebApiForUserAsync>d__5.MoveNext()
   at PlayingWithBlazor.Pages.CallWebApi.<OnInitializedAsync>d__3.MoveNext() in C:\Users\AndySchneider\source\repos\PlayingWithBlazor\Pages\CallWebApi.razor:line 33

  This exception was originally thrown at this call stack:
    [External Code]

Inner Exception 1:
MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call. 

My Web API is pretty plain vanilla right now.

// GET: api/<SubscriberController>
        [Authorize]
        [HttpGet]
        public IEnumerable<Subscriber> Get()
        {
            return subscriberRepository.GetAllAsync().Result;
        }

From what I have gathered, it looks like Microsoft.Identity.Web is calling MSAL. Everything I have found so far in troubleshooting an error like this leads me to catching MSAL exceptions and working with AcquireTokenSilent. Because I am not using MSAL directly, I am not sure where I would need to go to add this error handling, or what to add , for that matter.

For what its worth, here is my Program.cs as well

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using PlayingWithBlazor.Data;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Identity.Client;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var initialScopes = builder.Configuration["DownstreamApi:Scopes"]?.Split(' ');

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAdB2C"))
        .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
            .AddDownstreamWebApi("DownstreamApi", builder.Configuration.GetSection("DownstreamApi"))
            .AddInMemoryTokenCaches();

builder.Services.AddControllersWithViews()
    .AddMicrosoftIdentityUI();


builder.Services.AddAuthorization(options =>
{
    // By default, all incoming requests will be authorized according to the default policy
    options.FallbackPolicy = options.DefaultPolicy;
});

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor()
    .AddMicrosoftIdentityConsentHandler();
builder.Services.AddSingleton<WeatherForecastService>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}


app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

1 Answer 1

1

I tried the scenario in my environment.

I have called something like below controller method :

MyController.cs

[Authorize]
        [HttpGet]
        public IEnumerable<Subscriber> Get()
        {
            var user = await _api.Me.Request().GetAsync();

          ViewData["ApiResult"] = user.DisplayName;
            return await _api.Me.Request().GetAsync().Result;
        }

Received same error:

MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.
Microsoft.Identity.Client.Internal.Requests.Silent.SilentRequest.ExecuteAsync(CancellationToken cancellationToken)
MicrosoftIdentityWebChallengeUserException: IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent

enter image description here

**On behalf flow is used while using the call with `CallWebApiForAppAsync`, which is not available for Azure AD B2C.**

Please check this b2c limitations · AzureAD/microsoft-identity-web Wiki · GitHub

As an alternative, you can request access tokens for downstream APIs using GetAccessTokenForUserAsync

And the use exception handler to handle if any issue persists And allow MicrosoftIdentityWebChallengeUserException to handle the exception in try-catch block while calling the user.

try
{
// other code
    ...
    ITokenAcquisition.GetAccessTokenForUserAsync(...)
//other code
}
catch (MicrosoftIdentityWebChallengeUserException)
{
    
    // catch  after capture happens with [AuthorizeForScopes] attribute 
    
    throw;
}
catch (Exception ex)
{
    exceptionMessage = ex.Message;
}

Make sure to give api permissions required and it has to be granted admin consent through portal or during authentication.

Then call to my API can be successful:

enter image description here

Reference : blazor-server-authorized-downstream-api-call-with-azure-ad-b2c

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.