Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TokenAcquisition Exception since adding Azure Signal R Service #1875

Open
johnnyjones09 opened this issue Dec 1, 2023 · 1 comment
Open
Labels
pending-customer-confirmation Suggestions provided, waiting for the customer's confirmation

Comments

@johnnyjones09
Copy link

I recently added the Azure Signal R service to my .NET 6 blazor server application. My application is connecting to the service successfully in azure and that part looks good. My application communicates with an API to retrieve its data, before calling the API I have a DelegatingHandler which gets a token from azure with the required scope for that API. Once retrieved it added the token to the headers and sends the request. This has worked fine until Azure Signal R was added. I'm now getting the following exception and don't understand why.

IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent. . MSAL.NetCore.4.54.1.0.MsalUiRequiredException:
ErrorCode: user_null
Microsoft.Identity.Client.MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call.

I also noticed one part of the application that retrieves a cookie from httpcontext is no longer working. Is this because SignalR doesnt have access to the httpcontext?

Below is my startup code and the code from the delegating handler

 using System.Net.Http.Headers;
 using System.Net;
 using Microsoft.Identity.Web;
 using System.Security.Claims;

namespace BlazorApp.Handlers
{
    public class AuthenticationDelegatingHandler : DelegatingHandler
    {
        private readonly ITokenAcquisition _tokenAcquisition;
        private readonly IConfiguration _configuration;
        private readonly ILogger<AuthenticationDelegatingHandler> _logger;

        public AuthenticationDelegatingHandler(ITokenAcquisition tokenAcquisition, IConfiguration configuration, ILogger<AuthenticationDelegatingHandler> logger)
        {                      
            _tokenAcquisition = tokenAcquisition ?? throw new ArgumentNullException(nameof(tokenAcquisition));
            _configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var scopes = new[] { _configuration["ApiScope"] };
            string accessToken = string.Empty;

            try
            {
                accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes!);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error while fetching access token for communication with API. Details: {Message}. {InnerException}", ex.Message, ex.InnerException);
                throw;
            }                        

            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            var response = await base.SendAsync(request, cancellationToken);            
            return response;
        }
    }
}

Some key start up services being setup:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddLogging();
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(options =>
    {
        builder.Configuration.Bind("AzureAdB2C", options);        
    })
    .EnableTokenAcquisitionToCallDownstreamApi(new string[] { builder.Configuration["ApiScope"] })
    .AddInMemoryTokenCaches(); 

builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
})
.AddMicrosoftIdentityUI();
builder.Services.AddRazorPages();
builder.Services.AddHttpContextAccessor();
builder.Services.AddServerSideBlazor().AddMicrosoftIdentityConsentHandler();
builder.Services.AddScoped<NotificationService>();
builder.Services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; });
builder.Services.AddTransient<AuthenticationDelegatingHandler>();

builder.Services.AddHttpClient("WebAPI", client => client.BaseAddress = new Uri(builder.Configuration["ApiBaseAddress"] ?? string.Empty))
    .AddHttpMessageHandler<AuthenticationDelegatingHandler>();

builder.Services.AddHsts(options =>
{
    options.Preload = true;
    options.IncludeSubDomains = true;
    options.MaxAge = TimeSpan.FromDays(365);
});

builder.Services.AddHealthChecks();
RegisterTypes(builder.Services);
builder.Services.AddSignalR().AddAzureSignalR();

var app = builder.Build();
if (app.Environment.IsDevelopment() || builder.Environment.IsEnvironment("DEV"))
    app.UseDeveloperExceptionPage();    

app.UseHsts();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseRequestLocalization();
app.UseResponseHeaderProtection();
app.MapHealthChecks("/health");
app.MapControllers();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
    endpoints.MapBlazorHub();
    endpoints.MapFallbackToPage("/_Host");
});

app.Run();

Currently using Microsoft.Azure.SignalR - Version="1.22.0"

Thanks

@vicancy
Copy link
Member

vicancy commented Dec 20, 2023

I also noticed one part of the application that retrieves a cookie from httpcontext is no longer working. Is this because SignalR doesnt have access to the httpcontext?

When using Azure SignalR, HttpContext inside the Hub is reconstructed by Azure SignalR SDK. And since Azure SignalR is another domain, cookie is not passed through Azure SignalR to your app server, and so, cookie is no longer working after the HttpContext is reconstructed from Azure SignalR SDK.

When is this "WebAPI" httpclient used? Would you mind sharing with me a minimum repro-able project?

@vicancy vicancy added the pending-customer-confirmation Suggestions provided, waiting for the customer's confirmation label Dec 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pending-customer-confirmation Suggestions provided, waiting for the customer's confirmation
Projects
None yet
Development

No branches or pull requests

2 participants