Releases: cirreum/Cirreum.Runtime.Authentication
Release list
Release v1.1.0
Cirreum.Runtime.Authentication 1.1.0 — Live auth-event delivery
Why this release exists
Until now, the auth-event contracts in Cirreum.Kernel (IAuthenticationEvent, IAuthenticationEventPublisher, the four framework event records) had handlers but no delivery path: an admin action like "revoke this API key" or "force sign-out" had no way to reach a running replica. Revocation was correct at startup (boot hydration + the per-request fail-closed consult) but a credential revoked while a replica was running stayed usable there until that replica restarted.
This release ships the missing live-delivery leg. Together with the already-released consumers — the ApiKey denylist handler, the grant-cache invalidator in Cirreum.Domain, and the connection terminator in Cirreum.Services.Server — publishing one event now takes effect immediately, on every replica.
What's new
The default publisher, registered automatically. AddAuthentication(...) now registers InProcessAuthenticationEventPublisher (TryAdd — your own registration wins). Dispatch is synchronous and ordered: consumer handlers first, each isolated (a throwing handler is logged and the rest still run), transport bridges last — so an event never ships with unapplied local effects. Failures surface to the caller as an AggregateException; handlers are idempotent, so republishing is the safe retry. A single-replica app is complete with zero wiring:
public sealed class RevokeApiKeyHandler(IAuthenticationEventPublisher events) {
public async Task<Result> HandleAsync(RevokeApiKey command, CancellationToken ct) {
// ...revoke in the store (the durable, authoritative act)...
await events.PublishAsync(new CredentialRevoked(command.KeyId, command.Subject, DateTimeOffset.UtcNow) {
CredentialType = "apikey",
ExpiresAt = command.KeyExpiry,
}, ct);
return Result.Success();
}
}Cross-replica delivery: auth.AddEventCoordination(). Rides the Cirreum.Coordination broadcast primitive (ISignalBroadcaster) — Redis pub/sub in production, the safe in-process default otherwise:
builder.AddAuthentication(auth => auth
.AddApiKey(...)
.AddEventCoordination() // cross-replica auth-event delivery
.ConfigureCoordination(c => c.UseRedis())); // order-independentBehind the verb: a versioned event registry (Kernel [MessageVersion] machinery — the four framework events plus any public app-defined IAuthenticationEvent), an outbound sender, and an inbound receiver that dispatches wire events to local handlers except the senders themselves — a publish-receive loop is structurally impossible, and an ambient inbound-dispatch scope additionally bars wire re-entry from handlers that publish. The subscription opens in the ISystemInitializer phase, before any boot hydrator, closing the startup race by construction.
Scoped by default. Coordination state — including this channel — is namespaced to {applicationName}:{environmentName} automatically (both here and via ConfigureCoordination in Cirreum.AuthenticationProvider 1.2.0); an explicit WithScope(...) always wins.
Delivery semantics
At-most-once, unbuffered — a replica disconnected from the backend misses events published in that window, permanently. This is deliberate: boot hydration + the per-request fail-closed consult remain the durable correctness path; this channel is the low-latency leg. Two operational caveats: whoever can publish on the coordination connection can forge auth events (isolate it via UseRedis("connectionKey") when its writer set is broader than the app), and on Azure Managed Redis pub/sub does not cross active geo-replication regions — run region-local backends when active-active.
Compatibility
Additive minor. Nothing activates unless you call AddEventCoordination(); without it, behavior is identical to 1.0.x plus the (previously missing) in-process publisher. StackExchange.Redis becomes an ambient transitive dependency via the new direct Cirreum.Coordination.Redis reference — consistent with the umbrella's reference-everything/opt-in-via-code pattern.
This release also folds in an internal consolidation with no public-API or wire change: the event registry now takes its inbound (identifier, version) → type resolution from the shared Kernel registry base (dropping a duplicate assembly scan it used to carry), and the two internal delivery types were renamed to the framework's sender/receiver vocabulary. Apps touch neither — IAuthenticationEventPublisher and IAuthenticationEventHandler<TEvent> are unchanged, and the published IAuthenticationEventTransportBridge marker keeps its name.
See also
Cirreum.Coordination1.2.0 —ISignalBroadcaster,CoordinationScopeCirreum.Services.Server1.3.0 — connection registry + termination handlerCirreum.Authentication.ApiKey1.0.2 — denylist evict-on-expiry
Release v1.0.1
Release v1.0.0
Cirreum.Runtime.Authentication 1.0.0 — One package, one AddAuthentication() call
Cirreum.Runtime.Authentication is the app-facing umbrella for the Authentication pillar. Install this one package, call AddAuthentication(...) once, and the whole track wires up — the framework-shipped schemes, a dynamic forward scheme that picks the right one per request, the audience-routed claims transformer that produces your Cirreum IApplicationUser, and a boot-time validator that fails fast on misconfiguration. Only the schemes you configure activate.
Strictly additive — initial release. A new package in the Cirreum 1.0 Foundation Reset; no predecessor. Targets .NET 10.0.
Why this release exists
Wiring authentication by hand means composing six scheme packages, a per-request dispatch chain, a claims transformer, and a startup validator — and getting the order and the fail-fast behavior right. The umbrella does it behind a single call, so an app turns on exactly the schemes it wants and nothing it doesn't.
What's new
builder.AddAuthentication(...) — the one entry point
var builder = DomainApplication.CreateBuilder(args);
builder.AddAuthentication(auth => auth
.AddApiKey(options => { /* static clients and/or .AddResolver<T>() */ })
.AddSignedRequest<MyClientResolver>()
.AddSessionTicket());
// Oidc / Entra / External activate automatically from their
// Cirreum:Authentication:Providers:* configuration sections.
await using var app = builder.Build();
app.UseDefaultMiddleware(); // includes UseAuthentication() + UseAuthorization()One call composes the schemes, selectors, handlers, the dynamic forward scheme, and the claims transformer, then runs the boot-time validator. It must run on a Cirreum host (DomainApplication.CreateBuilder) — the audience providers branch on Web API vs Web App — and it's idempotent, returning a CirreumAuthenticationBuilder you can reuse.
Two ways a scheme turns on
- Configuration-declared —
Oidc,Entra,Externalactivate from theirCirreum:Authentication:Providers:*sections; presence of the section is the opt-in (no code call). - Code-composed —
ApiKey,SignedRequest,SessionTicketare enabled with a verb in the callback (AddApiKey,AddSignedRequest<T>,AddSessionTicket).
Every scheme's registration bails early when it isn't configured, so installing the package activates nothing you haven't asked for.
Per-request dispatch + fail-fast validation
AddAuthentication makes a dynamic forward scheme the default. Per request, a chain of selectors decides the handler: a conflict sentinel runs first and fails closed (401) when credentials for two different scheme categories are present; an audience selector routes Bearer JWTs to the matching configured provider; an anonymous fallback claims the rest so [AllowAnonymous] works. At startup, a Bearer-prefix validator ensures opaque-Bearer schemes (ApiKey, SessionTicket, …) declare unique token prefixes — failing fast on a collision rather than mis-routing at runtime.
CirreumAuthenticationBuilder
The builder the scheme packages extend — AddApiKey, AddSignedRequest<T>, AddSessionTicket, AddExternalTenantResolver<T>, AddApplicationUserResolver<T> — carrying the host IConfiguration so each verb can bind its own provider section.
How it pairs with the rest of the Authentication pillar
This umbrella transitively references all six Cirreum.Authentication.* scheme packages and the Cirreum.Runtime.AuthenticationProvider composition driver. Apps install only this package; the schemes and the driver flow in, and each scheme's own package documents its configuration and security model.
Compatibility
- Additive. Initial release.
- .NET 10.0. Requires a Cirreum host (
DomainApplication.CreateBuilder). - Transitively references the six scheme packages (ApiKey, SignedRequest, SessionTicket, Oidc, Entra, External),
Cirreum.Runtime.AuthenticationProvider, and the ASP.NET shared framework.
See also
CHANGELOG.md— condensed change list for1.0.0.README.md— full usage, scheme reference, and dispatch model.