Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refit and OAuth authentication in c#, why Http once again

I just found out about the Refit library on GitHub (link: https://github.com/reactiveui/refit) . Besides my first steps in this huge world, I tried to understand why the use of this library comes handy instead of the use of the usual HttpClient when we need to make http calls towards, for example, an API service. By reading around I understood the reason that creating the httpClient by ourselves, setting the headers and other configurations, is too old style and low-level. That's where Refit takes place. I then tried to make one step forward and read about the authentication part. I noticed, according to the github page of the library, that in order to make authentication work, we need to deal again with the HttpClient that we finally managed to get rid off. The example shown on the official page is:

class AuthenticatedHttpClientHandler : HttpClientHandler
{
    private readonly Func<Task<string>> getToken;

    public AuthenticatedHttpClientHandler(Func<Task<string>> getToken)
    {
        if (getToken == null) throw new ArgumentNullException("getToken");
        this.getToken = getToken;
    }

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // See if the request has an authorize header
        var auth = request.Headers.Authorization;
        if (auth != null)
        {
            var token = await getToken().ConfigureAwait(false);
            request.Headers.Authorization = new AuthenticationHeaderValue(auth.Scheme, token);
        }

        return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
    }
}

class LoginViewModel
{
    AuthenticationContext context = new AuthenticationContext(...);
    private async Task<string> GetToken()
    {
        // The AcquireTokenAsync call will prompt with a UI if necessary
        // Or otherwise silently use a refresh token to return
        // a valid access token 
        var token = await context.AcquireTokenAsync("http://my.service.uri/app", "clientId", new Uri("callback://complete"));

        return token;
    }

    public async void LoginAndCallApi()
    {
        var api = RestService.For<IMyRestService>(new HttpClient(new AuthenticatedHttpClientHandler(GetToken)) { BaseAddress = new Uri("https://the.end.point/") });

        var location = await api.GetLocationOfRebelBase();
    }
}

I am wondering what concept am I missing here. The purpose of the library is to use more high level code, setting interfaces that are enough to call an API service. This purpose is achieved before the authentication part because all the Http settings and so on are made on purpose under the hood. But as soon as we step in this field we find again HttpHandlers, HttpRequestMessages and HttpClients losing what's the purpose of the library itself. Can someone explain me please what am I missing in the bigger picture? thanks in advance

like image 753
Tarta Avatar asked May 13 '18 18:05

Tarta


People also ask

What is refit C#?

What is Refit? The Refit library for C# provides us with a type-safe wrapper for interacting with HTTP-based APIs. Instead of using HttpClient , which is provided for us by ASP.NET Core, we can define an interface that represents the API we want to interact with.

What is OAuth authentication in C#?

OAuth is a token based authorization mechanism for REST Web API. You develop the authorization with the API only once up until the expiration time of the token. The generated token is then used each time the REST Web API is called, saving an authorization step every time the REST Web API is called.

What is difference between DAuth and OAuth?

DAuth [25] is an extension of OAuth to split an access token into multiple sub-tokens and assign them to different components of a distributed web consumer. Therefore DAuth can support very fine-grained permission control for accessing user data in service providers. ...

What is OAuth 2.0 authentication and how it works?

OAuth 2.0, which stands for “Open Authorization”, is a standard designed to allow a website or application to access resources hosted by other web apps on behalf of a user. It replaced OAuth 1.0 in 2012 and is now the de facto industry standard for online authorization.


1 Answers

I've been trying to figure out authentication myself, here are my own observations in using Refit.

TL;DR: there are alternatives to set the authentication that do not require using the HttpClient, observations 2 and 3 below.

There are at least three way to handle authentication:

1) As noted in the GitHub page, you can pass in an HttpClient with an HttpClientHandler and in the handler set the Authorization header. In terms of why you need to use the handler, I have noticed that Refit will set the Authorization header to whatever value is specified in the attribute before making the HTTP request, if you set the header in the HttpClient prior to creating the Refit instance it will not work, for example this won't work:

[Get("/secretStuff")]
[Headers("Authorization: Bearer")]
Task<Location> GetLocationOfRebelBase();
. . .
var client = new HttpClient() { BaseAddress = new Uri("https://the.end.point/") };
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", someToken);
var api = RestService.For<IMyRestService>(client);
var location = await api.GetLocationOfRebelBase();

The Authorization header will be "Authorization: Bearer", the token will not be there. You need to alter the HttpClient just prior to the HTTP request is made, in the HttpClientHandler (or DelgatingHandler).

2) When creating a new instance of the Refit api client, pass in the base address to RestService.For rather than an HttpClient and specify the AuthorizationHeaderValueGetter, e.g.:

var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com", new RefitSettings {
   AuthorizationHeaderValueGetter = () => {
     var token = SomeMethodToGetAToken();
     Task.FromResult(token);
   }
});

3) Pass the token into the api method, e.g.:

[Get("/users/{user}")]
Task<User> GetUser(string user, [Header("Authorization")] string authorization);

This is mentioned in the Refit GitHub page: https://github.com/reactiveui/refit#dynamic-headers.

like image 166
davidp_1978 Avatar answered Sep 24 '22 02:09

davidp_1978