Skip to content

Commit

Permalink
BREAKING: Simplify authorization configuration (#1495)
Browse files Browse the repository at this point in the history
  • Loading branch information
anaisbetts authored Apr 17, 2023
1 parent 9276d6b commit 35965b8
Show file tree
Hide file tree
Showing 5 changed files with 13 additions and 40 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ var user = await GetUser("octocat", headers);
Most APIs need some sort of Authentication. The most common is OAuth Bearer authentication. A header is added to each request of the form: `Authorization: Bearer <token>`. Refit makes it easy to insert your logic to get the token however your app needs, so you don't have to pass a token into each method.

1. Add `[Headers("Authorization: Bearer")]` to the interface or methods which need the token.
2. Set either `AuthorizationHeaderValueGetter` or `AuthorizationHeaderValueWithParamGetter` in the `RefitSettings` instance. The difference is that the latter one passes the `HttpRequestMessage` into the function in case you need to take action based on the specific request. Refit will call your delegate each time it needs to obtain the token, so it's a good idea for your mechanism to cache the token value for some period within the token lifetime.
2. Set `AuthorizationHeaderValueGetter` in the `RefitSettings` instance. Refit will call your delegate each time it needs to obtain the token, so it's a good idea for your mechanism to cache the token value for some period within the token lifetime.

#### Reducing header boilerplate with DelegatingHandlers (Authorization headers worked example)
Although we make provisions for adding dynamic headers at runtime directly in Refit,
Expand Down Expand Up @@ -1242,7 +1242,6 @@ RestService.For<ISomeApi>(new HttpClient()
However, when supplying a custom `HttpClient` instance the following `RefitSettings` properties will not work:

* `AuthorizationHeaderValueGetter`
* `AuthorizationHeaderValueWithParamGetter`
* `HttpMessageHandlerFactory`

If you still want to be able to configure the `HtttpClient` instance that `Refit` provides while still making use of the above settings, simply expose the `HttpClient` on the API interface:
Expand All @@ -1264,7 +1263,7 @@ Then, after creating the REST service, you can set any `HttpClient` property you
```csharp
SomeApi = RestService.For<ISomeApi>("https://www.someapi.com/api/", new RefitSettings()
{
AuthorizationHeaderValueGetter = () => GetTokenAsync()
AuthorizationHeaderValueGetter = (rq, ct) => GetTokenAsync()
});

SomeApi.Client.Timeout = timeout;
Expand Down
12 changes: 2 additions & 10 deletions Refit.HttpClientFactory/HttpClientFactoryExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public static IHttpClientBuilder AddRefitClient<T>(this IServiceCollection servi
.ConfigureHttpMessageHandlerBuilder(builder =>
{
// check to see if user provided custom auth token
if (CreateInnerHandlerIfProvided(builder.Services.GetRequiredService<SettingsFor<T>>().Settings) is {} innerHandler)
if (CreateInnerHandlerIfProvided(builder.Services.GetRequiredService<SettingsFor<T>>().Settings) is { } innerHandler)
{
builder.PrimaryHandler = innerHandler;
}
Expand Down Expand Up @@ -115,15 +115,7 @@ public static IHttpClientBuilder AddRefitClient(this IServiceCollection services

if (settings.AuthorizationHeaderValueGetter != null)
{
innerHandler = new AuthenticatedHttpClientHandler((_, _) => settings.AuthorizationHeaderValueGetter(), innerHandler);
}
else if (settings.AuthorizationHeaderValueWithParamGetter != null)
{
innerHandler = new AuthenticatedHttpClientHandler((request, _) => settings.AuthorizationHeaderValueWithParamGetter(request), innerHandler);
}
else if (settings.AuthorizationHeaderValueWithCancellationTokenGetter != null)
{
innerHandler = new AuthenticatedHttpClientHandler(settings.AuthorizationHeaderValueWithCancellationTokenGetter, innerHandler);
innerHandler = new AuthenticatedHttpClientHandler(settings.AuthorizationHeaderValueGetter, innerHandler);
}
}

Expand Down
10 changes: 5 additions & 5 deletions Refit.Tests/AuthenticatedClientHandlerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public async void AuthenticatedHandlerIgnoresUnAuth()
var handler = new MockHttpMessageHandler();
var settings = new RefitSettings()
{
AuthorizationHeaderValueGetter = () => Task.FromResult("tokenValue"),
AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"),
HttpMessageHandlerFactory = () => handler
};

Expand All @@ -91,7 +91,7 @@ public async void AuthenticatedHandlerUsesAuth()
var handler = new MockHttpMessageHandler();
var settings = new RefitSettings()
{
AuthorizationHeaderValueGetter = () => Task.FromResult("tokenValue"),
AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"),
HttpMessageHandlerFactory = () => handler
};

Expand All @@ -114,7 +114,7 @@ public async void AuthenticatedHandlerWithParamUsesAuth()
var handler = new MockHttpMessageHandler();
var settings = new RefitSettings()
{
AuthorizationHeaderValueWithParamGetter = (request) => Task.FromResult("tokenValue"),
AuthorizationHeaderValueGetter = (request, _) => Task.FromResult("tokenValue"),
HttpMessageHandlerFactory = () => handler
};

Expand Down Expand Up @@ -293,7 +293,7 @@ public async void AuthentictedMethodFromBaseClassWithHeadersAttributeUsesAuth()
var handler = new MockHttpMessageHandler();
var settings = new RefitSettings()
{
AuthorizationHeaderValueGetter = () => Task.FromResult("tokenValue"),
AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"),
HttpMessageHandlerFactory = () => handler
};

Expand All @@ -316,7 +316,7 @@ public async void AuthentictedMethodFromInheritedClassWithHeadersAttributeUsesAu
var handler = new MockHttpMessageHandler();
var settings = new RefitSettings()
{
AuthorizationHeaderValueGetter = () => Task.FromResult("tokenValue"),
AuthorizationHeaderValueGetter = (_, __) => Task.FromResult("tokenValue"),
HttpMessageHandlerFactory = () => handler
};

Expand Down
16 changes: 3 additions & 13 deletions Refit/RefitSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public RefitSettings()
/// <param name="formUrlEncodedParameterFormatter">The <see cref="IFormUrlEncodedParameterFormatter"/> instance to use (defaults to <see cref="DefaultFormUrlEncodedParameterFormatter"/>)</param>
/// <param name="injectMethodInfoAsProperty">Controls injecting the <see cref="MethodInfo"/> of the method on the Refit client interface that was invoked into the HttpRequestMessage.Options (defaults to false)</param>
#else
/// <summary>
/// <summary>
/// Creates a new <see cref="RefitSettings"/> instance with the specified parameters
/// </summary>
/// <param name="contentSerializer">The <see cref="IHttpContentSerializer"/> instance to use</param>
Expand All @@ -61,17 +61,7 @@ public RefitSettings(
/// <summary>
/// Supply a function to provide the Authorization header. Does not work if you supply an HttpClient instance.
/// </summary>
public Func<Task<string>>? AuthorizationHeaderValueGetter { get; set; }

/// <summary>
/// Supply a function to provide the Authorization header. Does not work if you supply an HttpClient instance.
/// </summary>
public Func<HttpRequestMessage, Task<string>>? AuthorizationHeaderValueWithParamGetter { get; set; }

/// <summary>
/// Supply a function to provide the Authorization header. Does not work if you supply an HttpClient instance.
/// </summary>
public Func<HttpRequestMessage, CancellationToken, Task<string>>? AuthorizationHeaderValueWithCancellationTokenGetter { get; set; }
public Func<HttpRequestMessage, CancellationToken, Task<string>>? AuthorizationHeaderValueGetter { get; set; }

/// <summary>
/// Supply a custom inner HttpMessageHandler. Does not work if you supply an HttpClient instance.
Expand Down Expand Up @@ -113,7 +103,7 @@ public RefitSettings(
/// Optional Key-Value pairs, which are displayed in the property <see cref="HttpRequestMessage.Options"/> or <see cref="HttpRequestMessage.Properties"/>.
/// </summary>
public Dictionary<string, object> HttpRequestMessageOptions { get; set; }

#if NET6_0_OR_GREATER
/// <summary>
/// Controls injecting the <see cref="MethodInfo"/> of the method on the Refit client interface that was invoked into the HttpRequestMessage.Options (defaults to false)
Expand Down
10 changes: 1 addition & 9 deletions Refit/RestService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -149,15 +149,7 @@ public static HttpClient CreateHttpClient(string hostUrl, RefitSettings? setting

if (settings.AuthorizationHeaderValueGetter != null)
{
innerHandler = new AuthenticatedHttpClientHandler((_, _) => settings.AuthorizationHeaderValueGetter(), innerHandler);
}
else if (settings.AuthorizationHeaderValueWithParamGetter != null)
{
innerHandler = new AuthenticatedHttpClientHandler((request, _) => settings.AuthorizationHeaderValueWithParamGetter(request), innerHandler);
}
else if (settings.AuthorizationHeaderValueWithCancellationTokenGetter != null)
{
innerHandler = new AuthenticatedHttpClientHandler(settings.AuthorizationHeaderValueWithCancellationTokenGetter, innerHandler);
innerHandler = new AuthenticatedHttpClientHandler(settings.AuthorizationHeaderValueGetter, innerHandler);
}
}

Expand Down

0 comments on commit 35965b8

Please sign in to comment.