refit icon indicating copy to clipboard operation
refit copied to clipboard

[BUG] AuthorizationHeaderValueGetter ignored while using RefitSettings

Open mconca-kube opened this issue 4 years ago • 3 comments

If I use a custom HttpClient and custom RefitSettings, the AuthorizationHeaderValueGetter gets ignored and GetTokenAsync() is never called.

RestService.For<IAccountsClient>(
	new System.Net.Http.HttpClient()
	{
		BaseAddress = new Uri(apiIP + "Accounts"),
		Timeout = timeout
	}
	, new RefitSettings()
	{
		AuthorizationHeaderValueGetter = () => GetTokenAsync()
	});

This is the method in the Interface

[Headers("Authorization: Bearer")]
[Get("/EchoWithLogin")]
Task<string> EchoWithLoginAsync(string echoMessage);

Calling EchoWithLoginAsync does not add the token value to the header and the GetTokenAsync() method does not get called.

If insted I define the service as follows everything works fine, but I loose the timeout capability:

Accounts = RestService.For<IAccountsClient>(apiIP + "Accounts", new RefitSettings()
{
	AuthorizationHeaderValueGetter = () => GetTokenAsync()
});

mconca-kube avatar Sep 13 '21 15:09 mconca-kube

This is something I ran into the other day while trying to figure out why our logging handler wasn't calling our token provider/adding the bearer token to the headers. I believe this is intentional, although there doesn't appear to be anything in the README that implies this (that I could see). Looking at the source, however, you can see that there are a few properties on RefitSettings that will not work if you provide your own HttpClient instance:

This does actually make sense when you come to think about it; If you supply your own HttpClient instance it's not possible for Refit to set its own handler from the settings. You can only set a HttpMessageHandler from the constructors of HttpClient.

I was able to solve our issue by using RefitSettings.HttpMessageHandlerFactory instead of a supplying a HttpClient instance, as this allows the setting of the innerHandler that is passed to Refit.AuthenticatedHttpClientHandler, as can be seen here.

If I've understood what you're trying to do correctly; set a custom HttpClient.Timeout? I think you should be able to do something along the lines of this:

  1. Expose the HttpClient on your API interface declaration:
interface IAccountsClient
{
    // This will automagically be populated by Refit if the property exists
    HttpClient Client { get; }

    [Headers("Authorization: Bearer")]
    [Get("/EchoWithLogin")]
    Task<string> EchoWithLoginAsync(string echoMessage);
}
  1. Then, after creating the REST service, set the Timeout for the HttpClient:
Accounts = RestService.For<IAccountsClient>(apiIP + "Accounts", new RefitSettings()
{
    AuthorizationHeaderValueGetter = () => GetTokenAsync()
});

Accounts.Client.Timeout = timeout;

chowarth avatar Oct 10 '21 12:10 chowarth

@chowarth is correct. Any updates to the docs to clarify this are welcome!

clairernovotny avatar Oct 15 '21 17:10 clairernovotny

@chowarth Thank you, the HttpClient magic works.

kidmar avatar Oct 22 '21 07:10 kidmar