Rob King
Rob King

Reputation: 1201

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.

Upvotes: 4

Views: 8751

Answers (2)

Nicu Besliu
Nicu Besliu

Reputation: 513

You can use DI to inject your client where do you need it. We use it like this:

[ApiController]
public class ValuesController : ControllerBase
{
    private readonly ISomeApiClient_client;

    public ValuesController(ISomeApiClient client)
    {
        _client = client;
        httpClient.DefaultRequestHeaders.Authorization =
        new AuthenticationHeaderValue("Bearer", "Your Oauth token");
    }

    [HttpGet("/")]
    public async Task<ActionResult<Reply>> Index()
    {
        return await _client.GetMessageAsync();
    }
}

Upvotes: 1

Rob King
Rob King

Reputation: 1201

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>();

Upvotes: 9

Related Questions