Iām trying to use Microsoft.Identity.Web
to call an API from my .NET 6 Blazor server app. I can successfully login to authorized pages in my Blazor app but when I try to make an API call using CallWebApiForUserAsync
I get an inner exception of āNo account or login hint was passed to the AcquireTokenSilent callā.
The couple of posts here on Stack Overflow and the MS documentation look to me like I have it configured correctly. What am I missing?
appsettings.json:
"AzureAd": {
"Authority": "https://hivercom.b2clogin.com/XXXXXX.onmicrosoft.com/B2C_1_SignUpSignIn",
"Instance": "https://XXXXXX.b2clogin.com",
"TenantId": "XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
"ClientId": "XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX",
"CallbackPath": "/signin-oidc",
"Domain": "XXXXXX.onmicrosoft.com",
"SignedOutCallbackPath": "/signout/B2C_1_susi",
"SignUpSignInPolicyId": "B2C_1_SignUpSignIn",
"ResetPasswordPolicyId": "B2C_1_PasswordReset",
"EditProfilePolicyId": "B2C_1_EditProfile",
"ClientSecret": "XXXXXXXXXXXXXXXXXX"
},
"HiverAPI": {
"BaseUrl": "https://localhost:7075",
"Scopes": "https://XXXXXX.onmicrosoft.com/XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX/all"
},
Program.cs
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using BlazorB2C.Data;
using Microsoft.Identity.Web.TokenCacheProviders.InMemory;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpClient();
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "https://XXXXXX.onmicrosoft.com/XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX/all" })
.AddDownstreamWebApi("HiverService", builder.Configuration.GetSection("HiverAPI"))
.AddInMemoryTokenCaches();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddRazorPages().AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();
builder.Services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.Events.OnSignedOutCallbackRedirect = context =>
{
context.HttpContext.Response.Redirect(context.Options.SignedOutRedirectUri);
context.HandleResponse();
return Task.CompletedTask;
};
});
builder.Services.AddSingleton<WeatherForecastService>();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.Run();
Level.razor:
@page "/level"
@using Microsoft.Identity.Web
@inject IHttpClientFactory HttpClientFactory
@inject Microsoft.Identity.Web.ITokenAcquisition TokenAcquisitionService
@inject Microsoft.Identity.Web.IDownstreamWebApi DownstreamWebApi
@inject MicrosoftIdentityConsentAndConditionalAccessHandler ConsentHandler
@attribute [Authorize]
@attribute [AuthorizeForScopes(ScopeKeySection = "HiverAPI:Scopes")]
<PageTitle>Level</PageTitle>
<a href="MicrosoftIdentity/Account/SignOut">Log out</a>
<h3>Level</h3>
@code {
private const string ServiceName = "HiverService";
protected override async Task OnInitializedAsync()
{
try
{
error >> string token = await TokenAcquisitionService.GetAccessTokenForUserAsync(new string[] { "https://XXXXXX.onmicrosoft.com/XXXXXX-XXXXXX-XXXXXX-XXXXXX-XXXXXX/all" });
error >> var value = await DownstreamWebApi.CallWebApiForUserAsync(
ServiceName,
options =>
{
options.RelativePath = $"HiverUser";
});
}
catch (Exception ex)
{
var message = ex.Message;
ConsentHandler.HandleException(ex);
}
try
{
error >> await DownstreamWebApi.CallWebApiForUserAsync(
ServiceName,
options =>
{
options.HttpMethod = HttpMethod.Put;
options.RelativePath = $"HiverUser/0fd30e94-a116-4ef0-b222-4125546b8561";
});
}
catch (Exception ex)
{
var message = ex.Message;
ConsentHandler.HandleException(ex);
}
}
}
Azure configuration for client app:
Azure configuration for API