Concierge.Auth.Client.Keys
2.2.0
dotnet add package Concierge.Auth.Client.Keys --version 2.2.0
NuGet\Install-Package Concierge.Auth.Client.Keys -Version 2.2.0
<PackageReference Include="Concierge.Auth.Client.Keys" Version="2.2.0" />
<PackageVersion Include="Concierge.Auth.Client.Keys" Version="2.2.0" />
<PackageReference Include="Concierge.Auth.Client.Keys" />
paket add Concierge.Auth.Client.Keys --version 2.2.0
#r "nuget: Concierge.Auth.Client.Keys, 2.2.0"
#:package Concierge.Auth.Client.Keys@2.2.0
#addin nuget:?package=Concierge.Auth.Client.Keys&version=2.2.0
#tool nuget:?package=Concierge.Auth.Client.Keys&version=2.2.0
Concierge.Auth.Client.Keys
JWKS signing-key retrieval and peer public-key lookup against AuthService. Two separate, unrelated key systems (contract assumption #100) — kept in separate interfaces, separate storage, separate in-process caches. There is no shared "get a key" abstraction spanning both, and no code path by which a peer key could reach human-token verification.
JWKS keys (IJwksKeyProvider) |
Peer public keys (IPeerKeyClient) |
|
|---|---|---|
| Endpoint | GET /.well-known/jwks.json (public) |
GET /client-services/v1/:clientKey/public-key?target= (needs credential + grant) |
| Contract | §4.1, §5 | §10.4, §10.5 |
| Purpose | verify human JWTs | peer-to-peer crypto between two client services |
| Table | jwks_keys |
peer_keypairs |
Install and register
JWKS (IJwksKeyProvider) and peer public keys (IPeerKeyClient) register independently — pick
the one(s) this consumer actually needs.
JWKS only — human-token verification (the common case, no credential needed)
services.AddConciergeAuthClient(configuration, db => db.UseNpgsql(cs, npgsql =>
npgsql.MigrationsHistoryTable("__EFMigrationsHistory", "concierge"))); // base package — required first
services.AddConciergeAuthClientJwks(configuration); // binds "Concierge:AuthClient:Keys"
No Concierge.Auth.Client.Secrets registration, no client-service credential. A consumer that only
ever calls IJwksKeyProvider — e.g. an admin UI backend validating human JWTs — should stop here.
Peer public keys — service-to-service, requires a credential and an admin-issued grant
services.AddConciergeAuthClient(configuration, db => db.UseNpgsql(cs, npgsql =>
npgsql.MigrationsHistoryTable("__EFMigrationsHistory", "concierge")));
services.AddConciergeSecretManagement(configuration); // Secrets package — required first
services.AddConciergeAuthClientPeerKeys(configuration); // binds "Concierge:AuthClient:Keys"
AddConciergeAuthClientPeerKeys fails closed at this call, synchronously, if
AddConciergeSecretManagement(...) has not already been registered — peer-key lookup
authenticates with this service's own credential from IClientCredentialStore via
ConciergeClientCredentialHandler on the configured per-client header (default
X-Api-Key, from ConciergeSecretRotationOptions.HeaderName) — never a Bearer JWT and
never the keypair mechanism itself.
Both
services.AddConciergeSecretManagement(configuration);
services.AddConciergeAuthClientKeys(configuration); // convenience: registers JWKS + peer keys
AddConciergeAuthClientKeys is unchanged from before this split — it still registers both key
systems under one call, for a consumer that genuinely needs both. It also requires
AddConciergeSecretManagement to be registered first, same as AddConciergeAuthClientPeerKeys
alone.
JWKS — IJwksKeyProvider
var keys = await jwksKeyProvider.GetSigningKeysAsync(cancellationToken);
var key = await jwksKeyProvider.GetSigningKeyAsync(kid, cancellationToken);
Two cache layers: in-process (hot path) and the client's own jwks_keys table (so a cold
process start does not stampede AuthService — contract §5). TTL defaults to 1 hour
(cacheMaxAge), fetch rate is capped at 5/minute (jwksRequestsPerMinute) — applied to EVERY
fetch trigger, including an unknown kid, which is treated as a rotation signal (AuthService
serves both keys during rotation) rather than an immediate rejection. Concurrent callers during
a cold cache are coalesced into a single HTTP fetch.
Failure codes: JWKS_KEY_NOT_FOUND (kid unknown even after a permitted refresh),
JWKS_UNAVAILABLE (AuthService unreachable/unusable and no cache to fall back on).
Optional background warming
services.AddConciergeAuthClientJwks(o =>
{
o.EnableBackgroundRefresh = true; // default false
o.BackgroundRefreshInterval = TimeSpan.FromMinutes(15);
});
A plain IHostedService + PeriodicTimer — no Quartz.NET/Hangfire. Purely a cold-start
optimisation; lazy refresh on GetSigningKeysAsync/GetSigningKeyAsync is correct on its own.
Peer public keys — IPeerKeyClient
var result = await peerKeyClient.GetPeerPublicKeyAsync(targetClientKey, cancellationToken);
if (result.IsFailure)
{
// result.Error.Code is one of:
// PEER_KEY_DENIED — unknown target, no grant, revoked grant, or revoked key.
// ALL FOUR collapse to this SAME code (contract §10.4/§10.5) —
// do not attempt to distinguish which one occurred, and do not
// build retry logic assuming a denial had any server-side effect
// (denials stamp nothing).
// PEER_KEY_UNAVAILABLE — AuthService unreachable/unusable response, or local persist failed.
}
Authenticates with this service's own credential (ConciergeClientCredentialHandler attaches
the active secret from IClientCredentialStore on the configured per-client header, default
X-Api-Key) — never a Bearer JWT and never the keypair mechanism. A successful fetch persists
the target's public key to peer_keypairs with is_own = false and
no private-key material, and is served from an in-process TTL cache on subsequent lookups.
PeerPublicKey.TenantScope surfaces the tenant scope from the admin grant (contract §10.4):
null means unscoped (ALL tenants); a non-empty list restricts to those org-node ids. The field
is omitted on the wire for unscoped grants. Ids are opaque — enforce scope in your service, not
in this package.
Own peer keypair — IPeerKeypairStore
For outbound signing, import this service's own keypair after Auth admin provisioning (Flow A or B):
await peerKeypairStore.ImportOwnPeerKeypairAsync(publicKeyPem, privateKeyPem, cancellationToken);
var own = await peerKeypairStore.GetActiveOwnPeerKeypairAsync(cancellationToken);
Registered by AddConciergeAuthClientJwks / AddConciergeAuthClientPeerKeys /
AddConciergeAuthClientKeys. Private key is encrypted at rest (is_own = true); fingerprint is
computed inside the store (SHA-256 of SPKI). See libs/dotnet/docs/peer-key-onboarding.md.
Out of scope here
Token validation middleware and the Redis deny-list, credential rotation (see
Concierge.Auth.Client.Secrets), profile operations. No ASP.NET Core dependency in this package.
| 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
- Concierge.Auth.Client (>= 1.1.1)
- Concierge.Auth.Client.Secrets (>= 1.0.3)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Hosting.Abstractions (>= 10.0.11)
- Microsoft.Extensions.Http (>= 10.0.11)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 10.0.11)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Concierge.Auth.Client.Keys:
| Package | Downloads |
|---|---|
|
Concierge.Auth.Client.AuthGuard
ASP.NET Core authentication schemes for AuthService-issued credentials: AddConciergeSessionToken validates opaque session tokens (Redis cache + validate fallback, §11), AddConciergeJwtBearer validates client-credential JWTs (RS256/JWKS, typ guard, jti deny-list, client-revocation epoch), AddConciergePeerSignature validates peer-key RSA request signatures (Redis nonce replay protection), AddConciergeApiKey validates API keys against a host loader, plus WebSocket handshake support. The only Concierge.Auth.Client.* package referencing ASP.NET Core or StackExchange.Redis. |
|
|
Concierge.Auth.Client.PeerSignature
Peer-key HTTP request signing for the THISO Concierge.* client SDK: canonical payload builder, RSA PKCS#1 v1.5 + SHA-256 signatures, DelegatingHandler for X-Client-Key / X-Timestamp / X-Nonce / X-Signature headers, and store-backed private key resolution via IPeerKeypairStore with config PEM fallback. Verification lives in Concierge.Auth.Client.AuthGuard. |
GitHub repositories
This package is not used by any popular GitHub repositories.