Logo
  • Home
  • Overview packages
  • Concepts and terminology

Tutorials

  • Require authentication by default
  • Handling token expiration
  • Security middlewares overview
  • Server to server communication
    • Overview
    • Client credentials token request from a Web host
    • Manual client credential token request
    • Service calling multiple external APIs

Code lab

  • Client credentials flow (server to server)
    • Using IHttpClientFactory and Duende AccessToken Management
      • Steps
      • Sample using HttpClient
      • Sample using Refit
    • Bearer token request using client assertion
    • Bearer token request using shared secret
    • DPoP token request
    • Manual token request with Duende IdentityModel
FHI authentication and authorization extensions
  • Code lab
  • Client credentials flow (server to server)
  • Using IHttpClientFactory and Duende AccessToken Management
  • Edit on GitHub

Using IHttpClientFactory and Duende AccessToken Management¶

This code sample demonstrates how to configure an ASP.NET Core host to use Duende's client credentials token management. It shows how to register a client with the required token endpoint, client ID, and secret, and how to set up an HttpClient that automatically manages access tokens.

For a detailed explanation of the code flow, see the Web server host tutorial.

Steps¶

  1. Start the API using the WebAPI sample.
  2. Run the code below with .NET Interactive in VS Code or Jupyter Lab. You have the following options:
    1. Sample using HttpClient
    2. Sample using Refit

Sample using HttpClient¶

In [ ]:
Copied!
#!csharp
#load "../HttpLoggerHelper.csx"
#r "nuget: Duende.AccessTokenManagement, 3.2.0"
#r "nuget: Microsoft.Extensions.Hosting, 9.0.5"
#r "nuget: Microsoft.Extensions.Caching.Memory, 9.0.0"

using Microsoft.Extensions.Hosting;
using Duende.AccessTokenManagement;
using Microsoft.Extensions.DependencyInjection;
using System.Net.Http;

async Task RunAsync()
{
    var builder = Host.CreateDefaultBuilder();

    builder.ConfigureServices(services =>
    {
        services
            .AddClientCredentialsTokenManagement()
            .AddClient("m2m", options =>
            {
                options.TokenEndpoint = "https://demo.duendesoftware.com/connect/token";
                options.ClientId = "m2m";
                options.ClientSecret = "secret";
                options.Scope = "api";
            });

        services.AddClientCredentialsHttpClient("m2m", "m2m", client =>
        {
            client.BaseAddress = new Uri("https://localhost:7150");
        });

        services.AddDistributedMemoryCache();
        services.AddTransient<ITestService, TestService>();
    });

    var host = builder.Build();
    
    using var scope = host.Services.CreateScope();
    var testService = scope.ServiceProvider.GetRequiredService<ITestService>();
    await testService.Get();
}

interface ITestService
{
    public Task Get();
}

// A service that uses the registerd HttpClient with HttpClientFactory to make requests.
class TestService : ITestService
{
    private readonly IHttpClientFactory _factory;
    public TestService(IHttpClientFactory factory)
    {
        _factory = factory;
    }
    
    public async Task Get()
    {
        var client = _factory.CreateClient("m2m");
        var response = await client.GetAsync("api/v1/integration/health-records");
        await HttpLogger.LogRequest(response.RequestMessage);
        await HttpLogger.LogResponse(response);
    }
}

await RunAsync();
#!csharp #load "../HttpLoggerHelper.csx" #r "nuget: Duende.AccessTokenManagement, 3.2.0" #r "nuget: Microsoft.Extensions.Hosting, 9.0.5" #r "nuget: Microsoft.Extensions.Caching.Memory, 9.0.0" using Microsoft.Extensions.Hosting; using Duende.AccessTokenManagement; using Microsoft.Extensions.DependencyInjection; using System.Net.Http; async Task RunAsync() { var builder = Host.CreateDefaultBuilder(); builder.ConfigureServices(services => { services .AddClientCredentialsTokenManagement() .AddClient("m2m", options => { options.TokenEndpoint = "https://demo.duendesoftware.com/connect/token"; options.ClientId = "m2m"; options.ClientSecret = "secret"; options.Scope = "api"; }); services.AddClientCredentialsHttpClient("m2m", "m2m", client => { client.BaseAddress = new Uri("https://localhost:7150"); }); services.AddDistributedMemoryCache(); services.AddTransient(); }); var host = builder.Build(); using var scope = host.Services.CreateScope(); var testService = scope.ServiceProvider.GetRequiredService(); await testService.Get(); } interface ITestService { public Task Get(); } // A service that uses the registerd HttpClient with HttpClientFactory to make requests. class TestService : ITestService { private readonly IHttpClientFactory _factory; public TestService(IHttpClientFactory factory) { _factory = factory; } public async Task Get() { var client = _factory.CreateClient("m2m"); var response = await client.GetAsync("api/v1/integration/health-records"); await HttpLogger.LogRequest(response.RequestMessage); await HttpLogger.LogResponse(response); } } await RunAsync();

Sample using Refit¶

Note! This sample is not running due to a Refit. Refit uses C# source generators to generate the client code at compile-time — and source generators do not run in .NET Interactive (Jupyter)

In [ ]:
Copied!
#!csharp
#r "nuget: Duende.AccessTokenManagement, 3.2.0"
#r "nuget: Microsoft.Extensions.Hosting, 9.0.5"
#r "nuget: Microsoft.Extensions.Caching.Memory, 9.0.0"
#r "nuget: Refit, 8.0.0"
#r "nuget: Refit.HttpClientFactory, 8.0.0"

using Microsoft.Extensions.Hosting;
using Duende.AccessTokenManagement;
using Microsoft.Extensions.DependencyInjection;
using Refit;
using System.Net.Http;

async Task RunAsync()
{
    var builder = Host.CreateDefaultBuilder();

    builder.ConfigureServices(services =>
    {
        services
            .AddClientCredentialsTokenManagement()
            .AddClient("m2m", options =>
            {
                options.TokenEndpoint = "https://demo.duendesoftware.com/connect/token";
                options.ClientId = "m2m";
                options.ClientSecret = "secret";
                options.Scope = "api";
            });

        services.AddClientCredentialsHttpClient("m2m", "m2m", client =>
        {
            client.BaseAddress = new Uri("https://localhost:7150");
        })
        .AddTypedClient(RestService.For<IHealthRecordApi>);

        services.AddDistributedMemoryCache();
        services.AddTransient<ITestService, TestService>();
    });

    var host = builder.Build();
    
    using var scope = host.Services.CreateScope();
    var testService = scope.ServiceProvider.GetRequiredService<ITestService>();
    await testService.Get();
}

interface ITestService
{
    public Task Get();
}

// Using Refit to define the API contract
public record HealthRecordDto(string Name, string Description, DateTime CreatedAt);
public interface IHealthRecordApi
{
    [Refit.Get("/api/v1/integration/health-records")]
    Task<IEnumerable<HealthRecordDto>> GetHealthRecordsAsync();
}

// A service that uses the registerd RefitClient to make requests.
class TestService : ITestService
{
    private readonly IHealthRecordApi _healthRecordApi;
    public TestService(IHealthRecordApi healthRecordApi)
    {
        _healthRecordApi = healthRecordApi;
    }
    
    public async Task Get()
    {
        var response = await _healthRecordApi.GetHealthRecordsAsync();
        Console.WriteLine($"Health Records: {response}");
        foreach (var record in response)
        {
            Console.WriteLine($"- {record.Name}: {record.Description} (Created at: {record.CreatedAt})");
        }
    }
}

await RunAsync();
#!csharp #r "nuget: Duende.AccessTokenManagement, 3.2.0" #r "nuget: Microsoft.Extensions.Hosting, 9.0.5" #r "nuget: Microsoft.Extensions.Caching.Memory, 9.0.0" #r "nuget: Refit, 8.0.0" #r "nuget: Refit.HttpClientFactory, 8.0.0" using Microsoft.Extensions.Hosting; using Duende.AccessTokenManagement; using Microsoft.Extensions.DependencyInjection; using Refit; using System.Net.Http; async Task RunAsync() { var builder = Host.CreateDefaultBuilder(); builder.ConfigureServices(services => { services .AddClientCredentialsTokenManagement() .AddClient("m2m", options => { options.TokenEndpoint = "https://demo.duendesoftware.com/connect/token"; options.ClientId = "m2m"; options.ClientSecret = "secret"; options.Scope = "api"; }); services.AddClientCredentialsHttpClient("m2m", "m2m", client => { client.BaseAddress = new Uri("https://localhost:7150"); }) .AddTypedClient(RestService.For); services.AddDistributedMemoryCache(); services.AddTransient(); }); var host = builder.Build(); using var scope = host.Services.CreateScope(); var testService = scope.ServiceProvider.GetRequiredService(); await testService.Get(); } interface ITestService { public Task Get(); } // Using Refit to define the API contract public record HealthRecordDto(string Name, string Description, DateTime CreatedAt); public interface IHealthRecordApi { [Refit.Get("/api/v1/integration/health-records")] Task> GetHealthRecordsAsync(); } // A service that uses the registerd RefitClient to make requests. class TestService : ITestService { private readonly IHealthRecordApi _healthRecordApi; public TestService(IHealthRecordApi healthRecordApi) { _healthRecordApi = healthRecordApi; } public async Task Get() { var response = await _healthRecordApi.GetHealthRecordsAsync(); Console.WriteLine($"Health Records: {response}"); foreach (var record in response) { Console.WriteLine($"- {record.Name}: {record.Description} (Created at: {record.CreatedAt})"); } } } await RunAsync();
Previous Next

Built with MkDocs using a theme provided by Read the Docs.
GitHub « Previous Next »