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

Ability to more simply configure a scoped authorization token #1679

Open
DrLeh opened this issue Mar 28, 2024 · 3 comments
Open

Ability to more simply configure a scoped authorization token #1679

DrLeh opened this issue Mar 28, 2024 · 3 comments
Labels

Comments

@DrLeh
Copy link

DrLeh commented Mar 28, 2024

Is your feature request related to a problem? Please describe.

DelegatingHandlers have odd behavior where they get cached across requests, and it can be very difficult to register the authorization properly. User A makes request to service A, this service uses Refit to call to service B with a token for User A. User B goes through same code path, and if the handler is still cached, we will get the token for User A -> Service B even though user B is the one making the request.

Describe the solution you'd like

The RefitSettings allows us to have a simple Func for the auth header, but this is global and cannot rely on a scoped service (such as the current user information). If there was a way to have this Func also take an IServiceProvider parameter, that i could then resolve a scoped token out of.

Example:

var builder = services
    .AddRefitClient<IMyApi>()
    .ConfigureHttpClient(ConfigureHttpClient)
    .AddScopedAuthHeader((IServiceProvider sp) => sp.GetRequiredService<IMyScopedTokenProvider >().GetMyToken())
    ;

Describe alternatives you've considered

We try to use a handler like below, but because of weirdness with DI scopes, this sometimes fails. I have tried to make the ITokenProvider be based on AsyncLocal<string>, but we were still seeing this behavior from time to time.

public class AuthHeaderHandler : DelegatingHandler
{
    private readonly IServiceProvider _sp;

    public AuthHeaderHandler(IServiceProvider sp)
    {
        _sp = sp;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        string token = _sp.GetRequiredService<ITokenProvider>().GetToken();
        //sometimes this token^ is still for User A even though the request is made by User B
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
        return await base.SendAsync(request, cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
    }
    
    
    
var builder= services
    .AddRefitClient<IMyApi>()
    .ConfigureHttpClient(ConfigureHttpClient)
    .AddHttpMessageHandler<AuthHeaderHandler>()
    ;
}

Describe suggestions on how to achieve the feature

Someone who knows the ins and outs of DelegatingHandlers and how to configure the handler properly can make a working implementation and add an extension into Refit to make it a one-liner for those who have this situation.

Additional context

I believe this to be a very common use case that could be helpful to many others. We use Refit to connect all our microservices together and we need to be absolutely certain that each request is being sent with the right auth header, else we have a security issue.

@jonatr35
Copy link

+1 we have this exact issue in our system.

@armeldemarsac92
Copy link

+1 I am having this exact issue,

@velvolue
Copy link

velvolue commented Nov 7, 2024

I guess it depends on how the ITokenProvider is implemented. If you're using IHttpContextAccessor to get the current request's token, your message handler approach should be fine, e.g:

httpContextAccessor.HttpContext?.Request.Headers[HeaderNames.Authorization]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants