Cirreum.Authorization.ApiKey
1.0.19
dotnet add package Cirreum.Authorization.ApiKey --version 1.0.19
NuGet\Install-Package Cirreum.Authorization.ApiKey -Version 1.0.19
<PackageReference Include="Cirreum.Authorization.ApiKey" Version="1.0.19" />
<PackageVersion Include="Cirreum.Authorization.ApiKey" Version="1.0.19" />
<PackageReference Include="Cirreum.Authorization.ApiKey" />
paket add Cirreum.Authorization.ApiKey --version 1.0.19
#r "nuget: Cirreum.Authorization.ApiKey, 1.0.19"
#:package Cirreum.Authorization.ApiKey@1.0.19
#addin nuget:?package=Cirreum.Authorization.ApiKey&version=1.0.19
#tool nuget:?package=Cirreum.Authorization.ApiKey&version=1.0.19
Cirreum Authorization Provider - API Key
API key authentication provider for the Cirreum Framework
Overview
Cirreum.Authorization.ApiKey provides header-based API key authentication for ASP.NET Core applications within the Cirreum ecosystem. It enables secure service-to-service communication and broker authentication scenarios where OAuth/OIDC flows are not appropriate.
Key Features
- Header-based authentication - Validates API keys from configurable HTTP headers
- Multi-client support - Multiple clients can share the same header with unique keys
- Secure validation - Constant-time comparison prevents timing attacks
- Role-based authorization - Configure roles per client for fine-grained access control
- Seamless integration - Works alongside audience-based providers (Entra, Okta) in the same application
Dynamic API Key Resolution (NEW)
For scenarios with hundreds of partners/customers, use database-backed dynamic resolution:
- Efficient database lookup - Use
X-Client-Idheader to query only relevant keys - Built-in caching - Configurable TTL to reduce database load
- Composite resolvers - Chain config-based and database-backed resolvers
- Extensible base class - Implement
DynamicApiKeyClientResolverfor custom storage
Use Cases
- Service-to-service communication
- Broker applications pushing data to APIs
- External system integrations
- Background job authentication
- IoT device connectivity
Installation
dotnet add package Cirreum.Authorization.ApiKey
Configuration
Add API key clients to your appsettings.json:
{
"Cirreum": {
"Authorization": {
"Providers": {
"ApiKey": {
"Instances": {
"TrackBroker": {
"Enabled": true,
"HeaderName": "X-Api-Key",
"ClientId": "track-broker",
"ClientName": "Track Broker Application",
"Key": "your-secure-api-key-here",
"Roles": ["App.System"]
},
"ExternalService": {
"Enabled": true,
"HeaderName": "X-Api-Key",
"ClientId": "external-service",
"ClientName": "External Integration Service",
"Key": "different-secure-key",
"Roles": ["App.Agent"]
}
}
}
}
}
}
}
Configuration Properties
| Property | Required | Description |
|---|---|---|
Enabled |
Yes | Whether this client is active |
HeaderName |
Yes | HTTP header name to check (default: X-Api-Key) |
ClientId |
Yes | Unique identifier for the client, used in claims |
ClientName |
No | Display name for the client (defaults to ClientId) |
Key |
No* | The API key value (*or provide via ConnectionStrings:{InstanceName}) |
Roles |
No | Roles to assign to authenticated requests |
Secure Key Storage
API keys can be provided in two ways (checked in order):
- Direct value -
Keyproperty in instance configuration (dev/testing only) - Connection string -
ConnectionStrings:{InstanceName}in configuration (production)
For production environments, store API keys in Azure Key Vault using the connection string pattern:
{
"ConnectionStrings": {
"LapCastBroker": "@Microsoft.KeyVault(SecretUri=https://your-vault.vault.azure.net/secrets/LapCastBrokerKey)"
},
"Cirreum": {
"Authorization": {
"Providers": {
"ApiKey": {
"Instances": {
"LapCastBroker": {
"Enabled": true,
"HeaderName": "X-Api-Key",
"ClientId": "lapcast-broker",
"ClientName": "LapCast Broker",
"Roles": ["App.System"]
}
}
}
}
}
}
}
The instance name (LapCastBroker) is used as the connection string key, allowing both the API and client applications to resolve the same secret from Key Vault using configuration.GetConnectionString("LapCastBroker").
For local development, use user secrets or direct configuration:
{
"Cirreum": {
"Authorization": {
"Providers": {
"ApiKey": {
"Instances": {
"LapCastBroker": {
"Enabled": true,
"HeaderName": "X-Api-Key",
"ClientId": "lapcast-broker",
"Key": "dev-only-key"
}
}
}
}
}
}
}
Generating API Keys
For secure key generation, use RandomNumberGenerator:
var key = Convert.ToBase64String(RandomNumberGenerator.GetBytes(32));
Architecture
The provider follows the Cirreum header-based authorization pattern:
ApiKeyAuthorizationRegistrar
└── Extends HeaderAuthorizationProviderRegistrar
├── Registers clients in ApiKeyClientRegistry
├── Registers scheme via AuthorizationSchemeRegistry.RegisterHeaderScheme()
└── Configures ApiKeyAuthenticationHandler
ApiKeyAuthenticationHandler
├── Extracts key from configured header
├── Validates against ApiKeyClientRegistry
├── Builds ClaimsPrincipal with ClientId, ClientName, Roles
└── Uses constant-time comparison for security
ApiKeyAuthorizationInstanceSettings
└── Extends HeaderAuthorizationProviderInstanceSettings
└── HeaderName, ClientId, ClientName, Roles
Authentication Flow
- Request arrives with API key header (e.g.,
X-Api-Key: your-key) ForwardDefaultSelectordetects header and routes to API key schemeApiKeyAuthenticationHandlerextracts the key valueApiKeyClientRegistry.ValidateKey()performs secure comparison against all registered clients for that header- On match, handler builds
ClaimsPrincipalwith client identity and roles - Authorization policies evaluate roles as normal
Multi-Client Support
Multiple clients can use the same header name with different keys:
{
"ApiKey": {
"Instances": {
"ClientA": {
"HeaderName": "X-Api-Key",
"ClientId": "client-a",
"Key": "key-for-client-a",
"Roles": ["App.Admin"]
},
"ClientB": {
"HeaderName": "X-Api-Key",
"ClientId": "client-b",
"Key": "key-for-client-b",
"Roles": ["App.User"]
}
}
}
}
The ApiKeyClientRegistry validates the provided key against all clients registered for that header and returns the matching client, enabling different roles and identities per key.
Dynamic API Key Resolution
For large-scale deployments with many partners/customers, implement database-backed resolution:
Basic Setup
builder.AddAuthorization(auth => auth
.AddDynamicApiKeys<DatabaseApiKeyResolver>(
headers: ["X-Api-Key"],
options => options.WithCaching())
);
Implementing a Custom Resolver
public class DatabaseApiKeyResolver : DynamicApiKeyClientResolver {
private readonly IDbConnection _db;
public DatabaseApiKeyResolver(
IApiKeyValidator validator,
IOptions<ApiKeyValidationOptions> options,
IDbConnection db,
ILogger<DatabaseApiKeyResolver> logger)
: base(validator, options, logger) {
_db = db;
}
public override IReadOnlySet<string> SupportedHeaders =>
new HashSet<string> { "X-Api-Key" };
protected override async Task<IEnumerable<StoredApiKey>> LookupKeysAsync(
string headerName,
ApiKeyLookupContext context,
CancellationToken cancellationToken) {
// Use X-Client-Id header for efficient database lookup
var clientId = context.GetHeader("X-Client-Id");
if (!string.IsNullOrEmpty(clientId)) {
return await _db.QueryAsync<StoredApiKey>(
"SELECT * FROM ApiKeys WHERE ClientId = @ClientId AND IsActive = 1",
new { ClientId = clientId });
}
// Fallback: return all keys for the header (less efficient)
return await _db.QueryAsync<StoredApiKey>(
"SELECT * FROM ApiKeys WHERE HeaderName = @HeaderName AND IsActive = 1",
new { HeaderName = headerName });
}
}
With Caching
builder.AddAuthorization(auth => auth
.AddDynamicApiKeys<DatabaseApiKeyResolver>(
headers: ["X-Api-Key"],
options => options.WithCaching(caching => {
caching.DefaultExpiration = TimeSpan.FromMinutes(5);
caching.SlidingExpiration = TimeSpan.FromMinutes(1);
}))
);
Composite Resolution (Config + Database)
Static keys from appsettings are automatically checked first, then the dynamic resolver:
// Config keys (appsettings.json) + Database keys - automatic composite
builder.AddAuthorization(auth => auth
.AddDynamicApiKeys<DatabaseApiKeyResolver>(
headers: ["X-Api-Key"],
options => options.WithCaching())
);
Security Considerations
- Constant-time comparison - Key validation uses
CryptographicOperations.FixedTimeEqualsto prevent timing attacks - Key storage - Never commit API keys to source control; use Azure Key Vault or similar secret management
- Key rotation - Plan for key rotation by supporting multiple active keys during transition periods
- Transport security - Always use HTTPS to protect keys in transit
- Least privilege - Assign minimum required roles to each client
Claims
Authenticated requests receive the following claims:
| Claim | Value |
|---|---|
ClaimTypes.NameIdentifier |
ClientId |
ClaimTypes.Name |
ClientName |
ClaimTypes.Role |
Each configured role |
client_type |
api_key |
auth_scheme |
The scheme name |
License
This project is licensed under the MIT License - see the LICENSE file for details.
Cirreum Foundation Framework
Layered simplicity for modern .NET
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Cirreum.AuthorizationProvider (>= 1.0.26)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Cirreum.Authorization.ApiKey:
| Package | Downloads |
|---|---|
|
Cirreum.Runtime.Authorization
The Runtime Authorization configuration. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.19 | 121 | 5/7/2026 |
| 1.0.18 | 116 | 5/1/2026 |
| 1.0.17 | 125 | 4/28/2026 |
| 1.0.16 | 124 | 4/26/2026 |
| 1.0.15 | 124 | 4/14/2026 |
| 1.0.14 | 189 | 3/17/2026 |
| 1.0.12 | 115 | 3/17/2026 |
| 1.0.11 | 135 | 3/13/2026 |
| 1.0.10 | 104 | 3/12/2026 |
| 1.0.9 | 127 | 3/9/2026 |
| 1.0.8 | 105 | 3/6/2026 |
| 1.0.7 | 182 | 1/30/2026 |
| 1.0.6 | 137 | 1/21/2026 |
| 1.0.5 | 291 | 12/20/2025 |
| 1.0.4 | 132 | 12/20/2025 |
| 1.0.3 | 211 | 12/20/2025 |
| 1.0.1 | 323 | 12/16/2025 |
| 1.0.0 | 212 | 11/29/2025 |