Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING: Simplify authorization configuration #1495

Merged
merged 2 commits into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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