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¶
- Start the API using the WebAPI sample.
- Run the code below with .NET Interactive in VS Code or Jupyter Lab. You have the following options:
- Sample using HttpClient
- 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();