Skip to content

Authentication

Anrijs Vitolins edited this page Feb 22, 2022 · 5 revisions

Package has built in support for Basic authentication with username and password added as header to API calls. It has possibility to invoke method in your client to get some token/key from "outside".

Basic authentication

The only change to client setup is to add additional properties into its configuration object. Your configuration POCO class can still remain empty as necessary properties are defined in parent class:

public class ClientSettings : RestServiceSettings
{
}

When creating an object from this class to supply for your client class, in addition to mandatory BaseAdress you must specify authentication settings:

var apiClientSettings = new ClientSettings
{
    BaseAddress = "https://httpbin.org",
    Authentication = new RestServiceAuthentication
    {
        AuthenticationType = ApiAuthenticationType.Basic,
        UserName = "me",
        Password = "secret"
    }
};

If you want to use Microsoft.Extensions.Configuration to read this object from configuration, add something like this to your appsettings.json:

{
  "RestClient": {
    "BaseAddress": "https://httpbin.org",
    "Authentication": {
      "AuthenticationType": "Basic",
      "UserName": "me",
      "Password": "secret"
    }
  }
}

and then bind/get it into your class object:

var apiClientSettings = configuration.GetSection("RestClient").Get<ClientSettings>;

All the rest is magically done by RestClient - created header, Base64 encoded and sent with each service call.

External token

This will require configuration object changes as well:

var apiClientSettings = new ClientSettings
{
    BaseAddress = "https://httpbin.org",
    Authentication = new RestServiceAuthentication
    {
        AuthenticationType = ApiAuthenticationType.External
    }
};

If you want to use Microsoft.Extensions.Configuration to read this object from configuration, add something like this to your appsettings.json:

{
  "RestClient": {
    "BaseAddress": "https://httpbin.org",
    "Authentication": {
      "AuthenticationType": "External"
    }
  }
}

Addition to that you must override one of protected methods (sync or async) in RestClient base class to retrieve token from outside.

public class TypedClient : AbstractRestClient, ITypedClient
{
    private readonly ITokenRetreiver _authToke;

    // Here additional parameter should get external logic, which would return necessary token
    public TypedClient(HttpClient httpClient, ClientSettings settings, ILogger<TypedClient> logger, ITokenRetriever authToken) : base(httpClient, settings, logger) 
        => _authToken = authToken;


    // Overriding method to get Key-Value - sync method
    protected override (string Key, string Value) GetAuthenticationKeyValue()
    {
        string token = _authToken.GetToken();
        return new("Bearer", token);
    }

    // ------ OR ------

    // Overriding method to get Key-Value - async method
    protected override async Task<(string Key, string Value)> GetAuthenticationKeyValueAsync()
    {
        string token = await _authToken.GetTokenAsync();
        return new("Bearer", token);
    }
}

Completely external way

There is approaches with delegating handlers to HttpClient registration itself, which intercepts calls and adds authentication information to them. It is wired up at dependency injection level, like with IdentityModel:

services.AddHttpClient<ITypedClient, TypedClient>()
    .AddClientAccessTokenHandler();

If you use this approach - do not set any AuthenticationType in configuration (External will require method to exist - see above).