Search code examples
c#.net-corehttpclientmiddlewarerefit

Add a dynamic header to all outgoing Refit requests


I am using Refit (5.1.67) as my HttpClient wrapper, in a .NET Core 3.1 app using IHttpClientFactory.

The API I am calling is secured using a client credentials token.

I am registering the client with this:

services.AddRefitClient<ISomeApiClient>().ConfigureHttpClient(c =>
            c.BaseAddress = new Uri(Configuration["BaseUrlFromConfig"]));

The client has methods that look like this:

public interface ISomeApiClient
{
    [Get("/api/somewhere")]
    Task<IEnumerable<MyResponseObject>> GetItems([Header("X-User-Id")] string userId, [Header("Authorization")] string accessToken);

    [Get("/api/somewhere-else")]
    Task<MyResponseObject> GetItem([Header("X-User-Id")] string userId, [Header("Authorization")] string accessToken, int id);
}

What I want to avoid is having to explicitly pass accessToken and userId every time I call an endpoint (like above). Ideally, I want to have my client look like this:

public interface ISomeApiClient
{
    [Get("/api/somewhere")]
    Task<IEnumerable<MyResponseObject>> GetItems();

    [Get("/api/somewhere")]
    Task<IEnumerable<MyResponseObject>> GetItems(int id);
}

It feels like I need some sort of request middleware for outgoing requests, where I can add these two headers. If they were static I would just decorate the whole interface but because these are runtime values that will not work.

I cannot find any help on this one in the docs, and would appreciate any pointers.


Solution

  • Refit docs now explain how to do this

    https://github.com/reactiveui/refit#reducing-header-boilerplate-with-delegatinghandlers-authorization-headers-worked-example

    Add a header handler:

    class AuthHeaderHandler : DelegatingHandler
     {
        private readonly IAuthTokenStore authTokenStore;
    
        public AuthHeaderHandler(IAuthTokenStore authTokenStore)
        {
             this.authTokenStore = authTokenStore;
        }
    
        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var token = await authTokenStore.GetToken();
    
            //potentially refresh token here if it has expired etc.
    
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
    
            return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
        }
    }
    

    then register in Startup.cs when registering the client:

    services.AddTransient<AuthHeaderHandler>();
    
    services.AddRefitClient<ISomeThirdPartyApi>()
            .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"))
            .AddHttpMessageHandler<AuthHeaderHandler>();