DLeh
DLeh

Reputation: 24395

C# Refit client is not sending authorization header

I'm using a C# Refit client to have my services talk to one another via http.

I'm trying to send a Bearer token through the Authorization header, but according to the error message, it's not setting the AZ header in the request (see bottom). I've tried setting it through providing all headers, and using the [Authorize] attribute, and all the other methods they describe in their readme.

Here is my Refit client api call definition:


[Post(PresentationsBasePath + "/{presentationId}/cart")]
Task AddItemToCartAsync(long presentationId, ShoppingCartItemView item, [HeaderCollection] IDictionary<string, string> headers);

//calling it here:

await _api.AddItemToCartAsync(presentationId, item, GetTokenHeader(presentationId, token));

private Dictionary<string, string> GetTokenHeader(long presentationId, string token) => new()
{
    ["pres_id"] = presentationId.ToString(),
    [HeaderNames.Authorization] = $"Bearer {token}",
};

However, I'm getting a 401, and looking at the Refit.ApiException that's thrown, the RequestMessage.Headers does not contain the Authorization header.

Here's how I'm registering my refit api IPresentationsApi. I'm not doing anything relating to auth in the DI configuration


var refitSettings = GetRefitSettings();

void Configure<T>() where T : class => services
    .AddRefitClient<T>()
    .ConfigureHttpClient(ConfigureHttpClient);

Configure<IMarsPresentationApi>();
//other apis configured below

    
    private static void ConfigureHttpClient(IServiceProvider sp, HttpClient client)
    {
        var config = sp.GetRequiredService<IMarsConfiguration>();
        if (config.BaseUrl == null)
            throw new InvalidOperationException("Mars:BaseUrl must be configured");
        client.BaseAddress = new Uri(config.BaseUrl);
    }

Error shown here- you can see I get 401, and AZ header is not set in the request:

Error

What am I doing wrong? How do I get it to send the AZ header?

Upvotes: 4

Views: 5752

Answers (2)

Simon Needham
Simon Needham

Reputation: 543

This discussion continued on a GitHub issue for Refit. Somebody usefully pointed out that by default Authorization headers get stripped off when HttpClient follows a redirect - https://github.com/reactiveui/refit/issues/1374#issuecomment-1212776451.

I also hit the same issue described. After reading the suggestion in the GitHub issue discussion I configured my HttpClient instance that disabled auto redirects.

var httpClient = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = false })

This confirmed that the server API was returning 301-Moved Permanently responses to API endpoints that looked correct from the API documentation I had been given.

Looking at how I had configured my API endpoints they were configured like /{presentationId}/cart without slash at the end.

I updated the endpoints to end with a final slash /{presentationId}/cart/ and this stopped the server redirects being returned.

Upvotes: 0

Danut Radoaica
Danut Radoaica

Reputation: 2000

first try:

services.AddRefitClient<T>(new RefitSettings { AuthorizationHeaderValueGetter = () => Task.FromResult("TestToken") }).ConfigureHttpClient(ConfigureHttpClient);

second try:

services.AddRefitClient<T>().ConfigureHttpClient(ConfigureHttpClient).AddHttpMessageHandler<AuthorizationMessageHandler>();

where:

  public class AuthorizationMessageHandler : DelegatingHandler
  {
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancelToken)
    {
      HttpRequestHeaders headers = request.Headers;

      AuthenticationHeaderValue authHeader = headers.Authorization;

      if (authHeader != null)
        headers.Authorization = new AuthenticationHeaderValue(authHeader.Scheme, "TestToken");
        
      return await base.SendAsync(request, cancelToken);
    }
  }

Upvotes: 1

Related Questions