Problem
I was rewriting an old Angular application to Blazor Web Assembly a couple of days ago. The App is an internal tool, which uses a backend API that has Windows Authentication. In Angular, we used to add withCredentials: true
to HTTP interceptor to make it work. The most equivalent method in .NET is typically adding UseDefaultCredentials = true
in HttpClient. However, Blazor WASM will gives you an exception for this as indicated in this StackOverflow thread: WASM: System.PlatformNotSupportedException: System.Net.Http.HttpClientHandler is not supported on the current platform.
The majority of internet search result so far tell you it's not possible to call Windows Authentication API from Blazor. Really? Let's see how to make it work with a few lines of code.
Solution
Approach A
The original StackOverflow thread has 2 answers currently. The answer by ca8msm works, but the cost is not to use HttpClient
, that we need to do everything manually in order to add BrowserRequestCredentials.Include
to the request header. This approach sacrifices what we love about the HttpClient
, but gives you ultimate control over the http request details.
string APIURL = "https://localhost:44390/api/models";
// create request object and pass windows authentication credentials
var request = new HttpRequestMessage(HttpMethod.Get, APIURL);
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
// send the request and convert the results to a list
var httpResponse = await Http.SendAsync(request);
models = await httpResponse.Content.ReadFromJsonAsync<myModel[]>();
Approach B
I come up with a better approach, which can keep the HttpClient
we already like.
First, add a custom DelegatingHandler
, this is used for adding BrowserRequestCredentials.Include
to each request.
using Microsoft.AspNetCore.Components.WebAssembly.Http;
public class CredentialsMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
return base.SendAsync(request, cancellationToken);
}
}
Second, create your typed client as usual. I prefer typed client, you may also use HttpClientFactory
, it doesn't matter. You can find more information about how to make http request in best practice in this document.
public class CardClient
{
private readonly HttpClient http;
public CardClient(HttpClient http)
{
// ...
this.http = http;
}
// ...
}
Finally, register the client in DI, with the CredentialsMessageHandler
we wrote in the first step.
builder.Services.AddHttpClient<CardClient>(client => client.BaseAddress = new Uri(ApiEndpoint.FullUrl)).AddHttpMessageHandler<CredentialsMessageHandler>();
Now, you can still use the HttpClient
the way you always been using it with Windows Authentication enabled API!
BTW, Why I am not answering this in StackOverflow? Because I lost access to my account years ago :(
Daniel
Thank you for this article. It was quite helpfull. I suggest adding the necessary Package “Microsoft.Extensions.Http” to discover the dependency easier.
troy
Thanks a lot for this post. I was stuck on this. I still can't use AddHttpMessageHandler and other extension methods in my project for some reason, but I now have this set up, and futhermore can have a more aptly typed API client. Thanks!