0

I've to call a protected API during authorization. The API returns additional information for the user such as roles, groups, permissions ...

Both, the api and the blazor application, are registered in Azure AD B2C. Calling the API works after the authorization process is completed.

If I try to call the api during the event OnTokenValidated I'll get an error when trying to get a token.

ErrorCode: user_null Microsoft.Identity.Client.MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.

I've tried to implement the token acquisition like here: https://github.com/AzureAD/microsoft-identity-web/wiki/customization#how-to-query-microsoft-graph-on-token-validated

In Program.cs

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(options =>
    {
        builder.Configuration.GetSection("AzureAd").Bind(options);

        var prevOnTokenValidatedHandler = options.Events.OnTokenValidated;

        options.Events.OnTokenValidated = async context =>
        {
            await prevOnTokenValidatedHandler(context).ConfigureAwait(false);
            await AuthorizationHelper.ValidateAADAppToken(context);
        };
    }
    
    )
        .EnableTokenAcquisitionToCallDownstreamApi()
            .AddInMemoryTokenCaches();

In AuthorizationHelper

internal static async Task ValidateAADAppToken(Microsoft.AspNetCore.Authentication.OpenIdConnect.TokenValidatedContext context)
        {
           
            ITokenAcquisition ta = context.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();

            var scopes = new[] { "https://<Tenant>/<ApiId>/access_as_user" };
            //var accessToken = await ta.GetAccessTokenForUserAsync(scopes);
            var accessToken = Task.Run(() => ta.GetAccessTokenForUserAsync(scopes)).GetAwaiter().GetResult();


            HttpClient httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);

            var response = await httpClient.GetAsync("https://localhost:7297/WeatherForecast");


        }
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Markus
  • 1
  • Check this out https://stackoverflow.com/questions/74827877/cannot-get-a-blazor-server-app-to-call-a-secure-downstream-web-api-using-azure-a/74928813#74928813 – kavyaS Jun 23 '23 at 06:46

1 Answers1

0

If app has other scopes in the portal make sure to include them in the scopes before running to call downstream api for and check if admin has consented and make sure it is consented.

enter image description here

MsalUiRequiredException occurs if correct scopes and permissions are not assigned. so make sure that you have granted sufficient permissions to your application and granted admin consent to that permission.

Make use of [AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")] to filter the error.

Referred the code from: c# - MsalUiRequiredException when calling Microsoft Graph SDK from NET Core web app - Stack Overflow by qJake

var serviceProvider = services.BuildServiceProvider();
                var httpContextAccessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
                if (httpContextAccessor?.HttpContext?.User?.Identity?.IsAuthenticated ?? false)
                {
                    var tokenService = httpContextAccessor.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>();
                    try
                    {
                        token = await tokenService.GetAccessTokenForUserAsync(new[] { scopes });
                    }
                    catch (System.Exception ex)
                    {
                       ex.message();
                    }
                }

And use ExceptionHandler

enter image description here

app.UseExceptionHandler(new ExceptionHandlerOptions
{
    ExceptionHandler = async ctx => {
        var feature = ctx.Features.Get<IExceptionHandlerFeature>();
        if (feature?.Error is MsalUiRequiredException
            or { InnerException: MsalUiRequiredException }
           )
        {
            ctx.Response.Cookies.Delete($"{CookieAuthenticationDefaults.CookiePrefix}{CookieAuthenticationDefaults.AuthenticationScheme}");
            ctx.Response.Redirect(ctx.Request.GetEncodedPathAndQuery());
        }
    }
});

enter image description here

enter image description here

Reference: Blazor server authorized downstream API call with Azure AD B2C - Stack Overflow

kavyaS
  • 8,026
  • 1
  • 7
  • 19