Solving HttpClient Authentication with Delegating Handlers

August 10 2024

 

Many thanks to the sponsors who make it possible for this newsletter to be free for readers.

 

• Transform your API development process with Postman Flows! Experience a new way to visually create, debug, and automate complex API workflows with ease. Dive into the future of API management and enhance your productivity here.

 
 

What is Delegating Handler?

 
 

In C#/.NET, a DelegatingHandler is a special type of message handler that is part of the HTTP client pipeline used to process HTTP requests and responses.
It is a class that derives from HttpMessageHandler and is used to intercept and modify HTTP messages as they flow in and out of an HttpClient.

 

DelegatingHandler works by wrapping around another HttpMessageHandler.

 

When you send a request using HttpClient, the request travels through a chain of handlers, each possibly modifying the request or generating a response.

 

Eventually, the request reaches the innermost handler, typically the HttpClientHandler, which sends the request over the network.

 

This feature is particularly useful for tasks like logging, authentication, and other cross-cutting concerns.

 

Today I'm going to show how to implement it with authentication.

 
 

Configuring HttpClient in Program.cs

 
 


var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient<NewsletterService>(httpClient =>
{
    httpClient.BaseAddress = new Uri("https://api.newsletter.com");
});

var app = builder.Build();

app.Run();
What did we do here?

 

We have created Typed HttpClient - NewsletterService.

 

And we set BaseAddress to point to our API endpoint.

 

The NewsletterService is a class that will have 2 methods:

 

- Getting a user with a specified ID
- Getting Open rate value for issue with passed ID

public class NewsletterService(HttpClient client)
{
    public async Task<NewsletterUser?> GeEmailByIdAsync(string id)
    {
        var endpoint = $"users/{id}";

        return await client.GetFromJsonAsync<NewsletterUser>(endpoint);
    }

    public async Task<double> GetOpenRateAsync(string id)
    {
        var endpoint = $"issues/{id}/open-rate";

        return await client.GetFromJsonAsync<double>(endpoint);
    }
}

 

All set.

 

When we call any of these 2 methods, we get 401 Unauthorized.

 

Why?

 

Because the API we're targeting requires a passed AccessToken in order to access it.

 

Okay, nothing difficult, right?

 

We will add to both methods the Authorization RequestHeader with the AccessToken.

 

No no. Today we will show a better way.

 

That's right, using a DelegatingHandler.

public class AuthenticationDelegatingHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        //Don't hardcode those values
        request.Headers.Add("Authorization", "secretAccessToken");
        request.Headers.Add("SomeOtherHeader", "someOtherValue");

        return base.SendAsync(request, cancellationToken);
    }
}
What have we achieved with this?

 

We gave the command:
"Before you send the HttpClient request, enrich it with these headers that I am passing on to you".

 

And yes, this applies to every request associated with the NewsletterService.

 

How?

 

So let's not forget to tell HttpClient to use the Handler we created.

 

We will do it in the following way:

builder.Services.AddTransient<AuthenticationDelegatingHandler>();

builder.Services.AddHttpClient<NewsletterService>(httpClient =>
{
    httpClient.BaseAddress = new Uri("https://api.newsletter.com");
})

 
 

Wrapping up

 
 

Today we have shown the most efficient way to solve Authentication with HttpClient. We used TypedClient and DelegateHandler.

 

DelegatingHandler is especially powerful in scenarios where you need to apply consistent modifications or checks to requests/responses in a clean and reusable way.

 

For example, in a microservices architecture, you might use several handlers to handle concerns like logging, error handling, and retry policies before a request reaches an external service or database.

 

This design promotes separation of concerns and reusability across different parts of your application or across different applications within an organization.

 

Try to use the same approach to handle some other stuff like we did authentication today.

 

That's all from me today.

Join 13,250+ subscribers to improve your .NET Knowledge.

There are 3 ways I can help you:

Design Patterns Simplified ebook

Go-to resource for understanding the core concepts of design patterns without the overwhelming complexity. In this concise and affordable ebook, I've distilled the essence of design patterns into an easy-to-digest format. It is a Beginner level. Check out it here.


Sponsorship

Promote yourself to 13,250+ subscribers by sponsoring this newsletter.


Join TheCodeMan.net Newsletter

Every Monday morning, I share 1 actionable tip on C#, .NET & Arcitecture topic, that you can use right away.


Subscribe to
TheCodeMan.net

Subscribe to the TheCodeMan.net and be among the 13,250+ subscribers gaining practical tips and resources to enhance your .NET expertise.