![]() |
VOOZH | about |
dotnet add package Workleap.Extensions.Http.Authentication.ClientCredentialsGrant --version 2.4.0
NuGet\Install-Package Workleap.Extensions.Http.Authentication.ClientCredentialsGrant -Version 2.4.0
<PackageReference Include="Workleap.Extensions.Http.Authentication.ClientCredentialsGrant" Version="2.4.0" />
<PackageVersion Include="Workleap.Extensions.Http.Authentication.ClientCredentialsGrant" Version="2.4.0" />Directory.Packages.props
<PackageReference Include="Workleap.Extensions.Http.Authentication.ClientCredentialsGrant" />Project file
paket add Workleap.Extensions.Http.Authentication.ClientCredentialsGrant --version 2.4.0
#r "nuget: Workleap.Extensions.Http.Authentication.ClientCredentialsGrant, 2.4.0"
#:package Workleap.Extensions.Http.Authentication.ClientCredentialsGrant@2.4.0
#addin nuget:?package=Workleap.Extensions.Http.Authentication.ClientCredentialsGrant&version=2.4.0Install as a Cake Addin
#tool nuget:?package=Workleap.Extensions.Http.Authentication.ClientCredentialsGrant&version=2.4.0Install as a Cake Tool
| Description | Download link | Build status |
|---|---|---|
| Client-side library for any .NET application | 👁 nuget |
👁 build |
| Server-side library for ASP.NET Core web applications | 👁 nuget |
👁 build |
This set of two libraries enables authenticated machine-to-machine HTTP communication between a .NET application and an ASP.NET Core web application. HTTP requests are authenticated with JSON web tokens (JWT) issued by an OAuth 2.0 authorization server using the client credentials grant flow.
┌────────────────────────────────┐
┌─────────►│ OAuth 2.0 authorization server │◄──────────┐
│ └────────────────────────────────┘ │
│ │
│ get token with get signing keys │
│ client credentials grant flow │ validate
│ │ token
┌─┴───────────┐ ┌───────────────┴────────┐
│ Client .NET ├──────────────────────────►│ Protected ASP.NET Core │
│ application │ authenticated HTTP call │ service │
└─────────────┘ └────────────────────────┘
The client-side library includes:
The server-side library includes:
Requirements and Considerations:
<AUTHORITY>/.well-known/openid-configuration, as described in RFC 8414.Install the package Workleap.Extensions.Http.Authentication.ClientCredentialsGrant in your client-side application
that needs to communicate with the protected ASP.NET Core server. Then, use one of the following methods to configure an authenticated HttpClient:
// Method 1: directly set the options values with C# code
services.AddHttpClient("MyClient").AddClientCredentialsHandler(options =>
{
options.Authority = "<oauth2_authorization_server_base_url>";
options.ClientId = "<oauth2_client_id>";
options.ClientSecret = "<oauth2_client_secret>"; // use a secret store instead of hardcoding the value
options.Scope = "<optional_requested_scope>"; // use "Scopes" for multiple values
});
// Method 2: bind the options to a configuration section
services.AddHttpClient("MyClient").AddClientCredentialsHandler(configuration.GetRequiredSection("MyConfigSection").Bind);
// Method 3: Lazily bind the options to a configuration section
services.AddHttpClient("MyClient").AddClientCredentialsHandler();
services.AddOptions<ClientCredentialsOptions>("MyClient").Bind(configuration.GetRequiredSection("MyConfigSection"));
// appsettings.json:
{
"MyConfigSection": {
"Authority": "<oauth2_authorization_server_base_url>",
"ClientId": "<oauth2_client_id>",
"ClientSecret": "<oauth2_client_secret>", // use a secret configuration provider instead of hardcoding the value
"Scope": "<optional_requested_scope>", // use "Scopes" for multiple values,
"EnforceHttps": "<boolean>", // use EnforceHttps to force all authenticated to be sent via https
}
}
// You can also use the generic HttpClient registration with any of these methods:
services.AddHttpClient<MyClient>().AddClientCredentialsHandler( /* [...] */);
Note on EnforceHttps.
It is possible to allow http authenticated requests, however, this should be limited to exceptional scenarios.
It is strongly advised that you always use https for authenticated requests transmitted as the token sent will be in clear.
Then, instantiate the HttpClient later on using IHttpClientFactory or directly inject it in the constructor if you used the generic registration:
public class MyClient
{
private readonly HttpClient _httpClient;
public MyClient(IHttpClientFactory httpClientFactory)
{
this._httpClient = httpClientFactory.CreateClient("MyClient");
}
public async Task DoSomeAuthenticatedHttpCallAsync()
{
await this._httpClient.GetStringAsync("https://myservice");
}
}
Starting from version 1.3.0, tokens are pre-fetched and cached at app startup.
Subsequently, there is a periodic refresh of the token before its expiration and cache eviction.
This behavior can be disabled by setting ClientCredentialsOptions.EnablePeriodicTokenBackgroundRefresh to false.
This client-side library is based on Duende.AccessTokenManagement, Copyright (c) Brock Allen & Dominick Baier, licensed under the Apache License, Version 2.0.
The server-side library add the RequireClientCredentials attribute that simplify the use of the client credentials flow in your ASP.NET Core application:
[RequireClientCredentials("read")]scope, scp, http://schemas.microsoft.com/identity/claims/scope)read, {Audience}:read)Install the package Workleap.AspNetCore.Authentication.ClientCredentialsGrant in your server-side ASP.NET Core application and register the authentication services:
// Registers Microsoft's JwtBearer handler with a default "ClientCredentials" authentication scheme.
// This authentication scheme can be changed using other methods overloads.
builder.Services.AddAuthentication().AddClientCredentials();
This will automatically bind the configuration section Authentication:Schemes:ClientCredentials (unless you've changed the authentication scheme).
For instance, the example above works well with this appsettings.json:
{
"Authentication": {
"Schemes": {
"ClientCredentials": {
"Authority": "<oauth2_authorization_server_base_url>",
"Audience": "<audience>",
"MetadataAddress": "<oauth2_authorization_server_metadata_address>"
}
}
}
}
Next, protect your endpoints with the RequireClientCredentials attribute:
// When using Controlled-Based
[HttpGet]
[Route("weather")]
[RequireClientCredentials("read")]
public async Task<IActionResult> GetWeather()
{...}
// When using Minimal APIs
app.MapGet("/weather", () => {...}).RequireClientCredentials("read");
Next, register the authorization services which all the required authorization policies:
builder.Services
.AddClientCredentialsAuthorization();
Finally, register the authentication and authorization middlewares in your ASP.NET Core app.
var app = builder.Build();
// [...]
app.UseAuthentication();
app.UseAuthorization();
// [...] Map your endpoints
If you are using Swashbuckle to document your API, the [RequireClientCredentials] attribute will automatically populate the security definitions and requirements in the OpenAPI specification. For minimal APIs, there is a corresponding RequireClientCredentials() method.
For example:
// Controlled-based approach
[HttpGet]
[Route("weather")]
[RequireClientCredentials("read")]
public async Task<IActionResult> GetWeather()
{ /* ... */ }
// Minimal APIs
app.MapGet("/weather", () => { /* ... */ }).RequireClientCredentials("read");
Will generate this:
paths:
/weather:
get:
summary: 'Required scope: read.'
responses:
'200':
description: OK
'401':
description: Unauthorized
'403':
description: Forbidden
security:
- clientcredentials:
- target-entity:b108bbc9-538e-403b-9faf-e5cd874eb17f:read # Based on the provided JwtBearerOptions.Audience
components:
securitySchemes:
clientcredentials:
type: oauth2
flows:
clientCredentials:
tokenUrl: https://localhost:9020/oauth2/token # Based on provided ClientCredentials.Authority
scopes:
target-entity:b108bbc9-538e-403b-9faf-e5cd874eb17f: Request all permissions for specified client ID
target-entity:b108bbc9-538e-403b-9faf-e5cd874eb17f:read: Request permission 'read' for specified client ID
The project can be built by running Build.ps1. It uses Microsoft.CodeAnalysis.PublicApiAnalyzers to help detect public API breaking changes. Use the built-in roslyn analyzer to ensure that public APIs are declared in PublicAPI.Shipped.txt, and obsolete public APIs in PublicAPI.Unshipped.txt.
A new preview NuGet package is automatically published on any new commit on the main branch. This means that by completing a pull request, you automatically get a new NuGet package.
When you are ready to officially release a stable NuGet package by following the SemVer guidelines, simply manually create a tag with the format x.y.z. This will automatically create and publish a NuGet package for this version.
Copyright © 2023, Workleap. This code is licensed under the Apache License, Version 2.0. You may obtain a copy of this license at https://github.com/workleap/gsoft-license/blob/master/LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 net5.0 was computed. net5.0-windows net5.0-windows was computed. net6.0 net6.0 was computed. net6.0-android net6.0-android was computed. net6.0-ios net6.0-ios was computed. net6.0-maccatalyst net6.0-maccatalyst was computed. net6.0-macos net6.0-macos was computed. net6.0-tvos net6.0-tvos was computed. net6.0-windows net6.0-windows was computed. net7.0 net7.0 was computed. net7.0-android net7.0-android was computed. net7.0-ios net7.0-ios was computed. net7.0-maccatalyst net7.0-maccatalyst was computed. net7.0-macos net7.0-macos was computed. net7.0-tvos net7.0-tvos was computed. net7.0-windows net7.0-windows was computed. net8.0 net8.0 was computed. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 netcoreapp2.0 was computed. netcoreapp2.1 netcoreapp2.1 was computed. netcoreapp2.2 netcoreapp2.2 was computed. netcoreapp3.0 netcoreapp3.0 was computed. netcoreapp3.1 netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 netstandard2.0 is compatible. netstandard2.1 netstandard2.1 was computed. |
| .NET Framework | net461 net461 was computed. net462 net462 was computed. net463 net463 was computed. net47 net47 was computed. net471 net471 was computed. net472 net472 was computed. net48 net48 was computed. net481 net481 was computed. |
| MonoAndroid | monoandroid monoandroid was computed. |
| MonoMac | monomac monomac was computed. |
| MonoTouch | monotouch monotouch was computed. |
| Tizen | tizen40 tizen40 was computed. tizen60 tizen60 was computed. |
| Xamarin.iOS | xamarinios xamarinios was computed. |
| Xamarin.Mac | xamarinmac xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos xamarinwatchos was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.4.1-preview.1 | 42 | 6/14/2026 |
| 2.4.0 | 188 | 6/9/2026 |
| 2.3.1-preview.19 | 38 | 6/9/2026 |
| 2.3.1-preview.18 | 47 | 6/7/2026 |
| 2.3.1-preview.17 | 52 | 5/31/2026 |
| 2.3.1-preview.16 | 50 | 5/30/2026 |
| 2.3.1-preview.15 | 69 | 3/31/2026 |
| 2.3.1-preview.14 | 73 | 3/30/2026 |
| 2.3.1-preview.13 | 69 | 3/29/2026 |
| 2.3.1-preview.12 | 63 | 3/26/2026 |
| 2.3.1-preview.11 | 61 | 3/19/2026 |
| 2.3.1-preview.10 | 65 | 3/18/2026 |
| 2.3.1-preview.9 | 70 | 3/15/2026 |
| 2.3.1-preview.8 | 69 | 3/14/2026 |
| 2.3.1-preview.7 | 70 | 3/12/2026 |
| 2.3.1-preview.6 | 75 | 3/11/2026 |
| 2.3.1-preview.5 | 61 | 3/9/2026 |
| 2.3.1-preview.4 | 67 | 3/6/2026 |
| 2.3.1-preview.3 | 63 | 3/4/2026 |
| 2.3.1-preview.2 | 64 | 3/1/2026 |