I've got a server-side Blazor / IdentityServer4 / API setup. With every request to the API I've got to send the access token that I got from the identity server. I get the access token from the HttpContext when my HttpClient gets created in Startup.cs:
services.AddHttpClient<IMyClient, MyClient>(client =>
{
var serviceProvider = services.BuildServiceProvider();
var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>();
var task = httpContextAccessor.HttpContext.GetTokenAsync("access_token");
task.Wait();
var accessToken = task.Result;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.BaseAddress = new Uri(Configuration.GetMyApiServerUrl());
});
Every component, that has to make calls to the API, injects MyClient. If such a component is created, the AddHttpClient function is called and the access token is set for future calls to the API.
This works well on my local machine but on the server, only the first call after page load works. After that, if a new component gets created that injects MyClient, the HttpContext is null inside the AddHttpClient function.
Any idea on how to solve this?
You shouldn't be using HttpContextAccessor in Blazor server-side applications. I think the whole approach you are taking here is problematic, as there is no HttpContext available in SignalR applications in most cases.
A doable approach would be to include the access_token as a claim inside the authenticated user as that is something that will be available to the app in all contexts and then make your handler use IAuthenticationStateProvider to resolve the current authentication state.
@SteveSandersonMS Is this doable?
@rynowak for suggestions about HttpClientFactory
@javiercn Yes, that sounds reasonable to me.
Closing as there's no action to be taken here.
The Identity Server puts the access token in the HTTP Header. As far as I know I can't change that. So I guess there is no other way for me than to get the access token out of the HttpContext on the first call. Then I can include it as a claim inside the authenticated user. Is that correct?
@rysep2 Yes. That should work.
I'm trying to get the user agent string in a server side app and running into the same issue. If not the HttpContextAccessor, what's the proper way to get info about the request in server side?
Hi @jdaless.
It looks like you are posting on a closed issue!
We're very likely to lose track of your bug/feedback/question unless you:
A doable approach would be to include the access_token as a claim inside the authenticated user as that is something that will be available to the app in all contexts and then make your handler use IAuthenticationStateProvider to resolve the current authentication state.
I changed my code accordingly but when I try to access the AuthenticationStateProvider in my HttpMessageHandler I get the following error message "System.InvalidOperationException: GetAuthenticationStateAsync was called before SetAuthenticationState.". This happens after the log in process, the AuthenticationState should already be set. Or am I wrong?
Startup.cs:
services.AddTransient<MyHttpMessageHandler>();
services.AddHttpClient<IMyClient, MyClient>(client =>
{
client.BaseAddress = new Uri(Configuration.GetMyApiServerUrl());
}).AddHttpMessageHandler<MyHttpMessageHandler>();
MyHttpMessageHandler.cs:
public class MyHttpMessageHandler : DelegatingHandler
{
private readonly AuthenticationStateProvider _authenticationStateProvider;
public MyHttpMessageHandler(AuthenticationStateProvider authenticationStateProvider)
{
_authenticationStateProvider = authenticationStateProvider;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
return await base.SendAsync(request, cancellationToken);
}
}
Is it possible to reopen this thread or do I have to create a new issue for this problem to get recognized?
This still is an issue, I can believe there is no official support for this yet since Authentication/Authorization should be considered a priority.
@javiercn looks like this hasn't been resolved as yet - https://github.com/aspnet/AspNetCore/issues/18066. Can you help?
Most helpful comment
This still is an issue, I can believe there is no official support for this yet since Authentication/Authorization should be considered a priority.