Search code examples
c#authorizationasp.net-core-webapidotnet-httpclient

Add Jwt token in header for every Http call using the concept of `HttpInterceptor` From angular for asp.net core web api


Is there any way to implement an interceptor so that I can call a microservice api from another microservices where all the http call will be intercepted & added jwt token in the header? So that, I don't have to set authorization token each time I request.

In angular there is a concept of HttpInterceptor. Where each http requests will be intercepted ans added jwt token in the header. Is there any way to achieve that in asp.net core web api?


Solution

  • A simple approach are named clients. Here you add a preconfigured HttpClient instance to your service registry and can access this instance wherever you need it:

    builder.Services.AddHttpClient("GitHub", httpClient =>
    {
        httpClient.BaseAddress = new Uri("https://api.github.com/");
    
        // using Microsoft.Net.Http.Headers;
        // The GitHub API requires two headers.
        httpClient.DefaultRequestHeaders.Add(
            HeaderNames.Accept, "application/vnd.github.v3+json");
        httpClient.DefaultRequestHeaders.Add(
            HeaderNames.UserAgent, "HttpRequestsSample");
    });
    

    Use the httpClient.Default* properties.

    See: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-6.0#named-clients

    The drawback is, that you don't know how requests must look like when using the instance. One approach to solve this is to create a so-called typed client. Basically a wrapper around HttpClient adding the right configuration and enforcing the correct request and response types.

    public class CatalogService : ICatalogService
    {
        private readonly HttpClient _httpClient;
        private readonly string _remoteServiceBaseUrl;
    
        public CatalogService(HttpClient httpClient)
        {
            _httpClient = httpClient;
        }
    
        public async Task<Catalog> GetCatalogItems(int page, int take, int? brand, int? type)
        {
            var uri = API.Catalog.GetAllCatalogItems(_remoteServiceBaseUrl, page, take, brand, type);
            var responseString = await _httpClient.GetStringAsync(uri);
    
            var catalog = JsonConvert.DeserializeObject<Catalog>(responseString);
            return catalog;
        }
    }
    

    (example from the docs here: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests)

    If you have static values (e.g. a fixed client secret), you can use options to inject them as described here: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-6.0

    If you get your token from another service, obviously just inject this other service.

    You can also configure the HttpClient when adding your typed client to the service registry:

    services.AddHttpClient<ICatalogService, CatalogService>(client =>
    {
        client.BaseAddress = new Uri(Configuration["BaseUrl"]);
    });
    

    Example from: https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests#multiple-ways-to-use-ihttpclientfactory

    Configuring the client here is similar to angular injectors in the way, that it separates configuration and client implementation. Example: You could use the same CatalogService class with a catalog server that expects an Authorization header and a server that expects "MySpecialAuth" header without having to take care of those differences in the CatalogService class.

    To show the differences in the flow...

    • Angular iterceptors: use shared http client > then intercept requests based on e.g. domain
    • C# clients: preconfigure clinet > then use configured instance

    Side notes:

    • You typically should not create new instances of HttpClient manually. Inject them using and use IHttpClientFactory in the background.