I created a new blazor server project using do.net 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();
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
**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:
Reference: blazor-server-authorized-downstream-api-call-with-azure-ad-b2c
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.