aspnetcore: Problem providing Access Token to HttpClient in Interactive Server mode
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
When making authenticated requests in InteractiveServer mode, a user’s access token is required to talk to an external service. As the guidance is that it is not safe to use the IHttpContextAccessor when in server interactive mode, I have been following the documentation to try and add a token provider servicer.
I’ve followed the documentation guides below, however the access token on the token provider in interactive server mode always comes through as null. I’m unsure if I have misunderstood or missed something in these guides or if the guides do not currently lead to a complete solution.
- Server-side ASP.NET Core Blazor additional security scenarios
- ASP.NET Core Blazor dependency injection
The sample project I have attached tries two different approaches to get this access token.
The first is the inject the TokenProvider into the WeatherService, and grab the token from it there. This works fine when using server side rendering, but the token is null when in interactive server mode.
The second is to try use a circuit handler to set the correct services for the circuit, allowing it to access the TokenProvider from inside other services by injecting the CircuitServicesAccessor. The circuit handler however never seems to get the CreateInboundActivityHandler, and so I have been unable to test whether the TokenProvider it would provide would contain a null access token or not.
Expected Behavior
When a HttpClient request is made in InteractiveServer mode, the TokenProvider configured in the App component should be passed to the WeatherService class so it can be used to set the Authentication header.
Alternatively, the AuthenticationStateHandler class should get the CircuitServicesAccessor set by the ServicesAccessorCircuitHandler, which can then be used to access the TokenProvider class to get the token.
Steps To Reproduce
I have created a sample solution which shows what I have attempted so far: https://github.com/RobJDavey/BlazorTokenIssue
The README explains how to run the solution. While there are 3 projects in the solution, 2 of them are purely there to support the demonstration, it’s only the BlazorApp service that is at issue.
To authenticate, please user the either username and password alice/alice or bob/bob as these are the test users configured.
The SSR page always loads the data from the external service fine, however the Interactive Server page fails due to the missing token.
Exceptions (if any)
A 401 is returned by the service when no valid access token is attached.
System.Net.Http.HttpRequestException: Response status code does not indicate success: 401 (Unauthorized).
at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
at BlazorApp.Services.WeatherForecastService.GetForecastAsync(Int32 skip, Int32 take) in ./BlazorApp/Services/WeatherForecastService.cs:line 34
at BlazorApp.Components.Pages.WeatherInteractive.<OnInitialized>b__8_0(GridItemsProviderRequest`1 request) in ./BlazorApp/Components/Pages/WeatherInteractive.razor:line 47
.NET Version
8.0.100
Anything else?
cc: @guardrex https://github.com/dotnet/AspNetCore.Docs/issues/31113
About this issue
- Original URL
- State: open
- Created 7 months ago
- Comments: 22 (4 by maintainers)
@RobJDavey I noticed that @mkArtakMSFT tagged your issue with
Doc. It made me curious, so I downloaded your solution and ran it.I set a breakpoint in the
OnInitializedAsyncmethod in theApp.razorcomponent,OnInitializedmethod in theWeatherInteractive.razorcomponent, and in theGetForecastAsyncmethod inWeatherForecastService. I then navigated to the page. and observe the order of breakpoints being hit.What I observed was that the component was created twice. The first time, your token was passed correctly, the
OnInitializedwas called, and the data was collected from your server via theWeatherForecastService. The second time, theOnInitializedwas called, as it was a new instance, no token was passed to the newWeatherForecastServiceinstance, and you obviously received a401response, as you should. This is because prerendering is enabled by default (more information on render modes here: ASP.NET Core Blazor render modes)So when you navigate to the
WeatherInteractivepage, I am seeing the following sequence of breakpoints being hit:This is happening when NavManager is used (via the NavLink component) and also with a regular anchor html element.
This does not happen with
StreamRendering. So when you navigate to theWeatherSsrpage, I am seeing the following sequence of breakpoints being hit:If I set the render mode to no prerender:
… then I am seeing the following sequence of breakpoints being hit:
I have not isolated why this is happening with your code and there is no simple work-around that I can see. I am not sure if this is a bug or by-design. Someone from Microsoft will have to chime in.