ExternalKeysServiceCollectionExtensions Class
Wires an IKeyCustodian (an HSM, a cloud KMS, or a vault transit engine) in two steps: WHICH custodian holds the keys, and HOW the library uses it. The backend packages supply the first; the placement calls here supply the second, so a custodian and a placement compose freely instead of multiplying into one method per pair.
public static class ExternalKeysServiceCollectionExtensionsInheritance System.Object → ExternalKeysServiceCollectionExtensions
Remarks
Both halves live in this package because both are about key material and neither is about any particular consumer of it. Whoever consumes the keys - an OpenID Provider publishing them at its JWKS endpoint, a transmitter signing security event tokens, a client protecting its own state - reads the recorded KeyPlacement and needs no registration call of its own.
Methods
ExternalKeysServiceCollectionExtensions.AddCustodian<TCustodian>(this IServiceCollection) Method
Registers TCustodian as the custodian and opens the placement choice. The custodian is
DI-constructed, so it may depend on the host's own services. A host whose custodian is already registered -
a typed HttpClient, or an instance it built itself - calls RequireKeyPlacement(this IServiceCollection) instead.
public static Abblix.Jwt.ExternalKeys.IKeyCustodianBuilder AddCustodian<TCustodian>(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)
where TCustodian : class, Abblix.Jwt.ExternalKeys.IKeyCustodian;Type parameters
TCustodian
The custodian implementation holding the private keys.
Parameters
services Microsoft.Extensions.DependencyInjection.IServiceCollection
The service collection to configure.
Returns
IKeyCustodianBuilder
The builder whose placement call completes the wiring.
Remarks
Do not combine this with ComposeExternalKeyBackends: the placement call performs that itself, and
Compose refuses the second composition on the spot, at the registration call rather than at
startup. Use this path, or that one, never both.
ExternalKeysServiceCollectionExtensions.AddInMemoryKeyRing(this IServiceCollection, LocalKeys) Method
Registers a key ring that mints its keys in this process and keeps them there: no custodian, no shared store, nothing to provision.
public static Microsoft.Extensions.DependencyInjection.IServiceCollection AddInMemoryKeyRing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, Abblix.Jwt.ExternalKeys.LocalKeys policy);Parameters
services Microsoft.Extensions.DependencyInjection.IServiceCollection
The service collection to add to.
policy LocalKeys
What to mint, how often, and how long to keep a retired key.
Returns
Microsoft.Extensions.DependencyInjection.IServiceCollection
The same collection, so calls chain.
Remarks
The answer for a host with no HSM or KMS, which is most of them. It rotates, and it keeps retired keys long enough that what they produced stays readable - the two things a ring is for.
What it does NOT do is share those keys with another process. Every replica mints its own, so anything one replica produced is unreadable by the others, and everything is gone when the process restarts. For a single instance that is exactly right and costs nothing. For more than one it is wrong, and wrong in the quiet way: nothing fails at startup, sign-ins simply break for whoever lands on the wrong replica.
So a host that has registered an IKeyRingStore - which is how keys are shared - is refused here rather than served: having registered one, it plainly expects sharing, and a ring that silently ignored it would be the worst of both. Use AddKeyRing(this IServiceCollection, MintedKeys) with a custodian instead.
ExternalKeysServiceCollectionExtensions.AddKeyRing(this IServiceCollection, MintedKeys) Method
Registers a key ring that mints its own keys, seals each to the custodian's key-encryption key, shares them through the registered IKeyRingStore, and rotates them on the policy's schedule.
public static Abblix.Jwt.ExternalKeys.IMintedKeysBuilder AddKeyRing(this Microsoft.Extensions.DependencyInjection.IServiceCollection services, Abblix.Jwt.ExternalKeys.MintedKeys policy);Parameters
services Microsoft.Extensions.DependencyInjection.IServiceCollection
The service collection to add to.
policy MintedKeys
What to mint, how often, and which key-encryption key seals it.
Returns
IMintedKeysBuilder
A builder for the call that supplies the store.
Remarks
This registers the ring and nothing else. What the ring's keys are then USED for is the caller's concern: an OpenID Provider publishes them at its JWKS endpoint, a client protects stored sessions with them. Neither of those belongs here, which is why this lives beside the key material rather than beside either consumer.
ExternalKeysServiceCollectionExtensions.RequireKeyPlacement(this IServiceCollection) Method
Requires the host to say where the private half of its keys lives, and hands it the builder to say it with.
public static Abblix.Jwt.ExternalKeys.IKeyCustodianBuilder RequireKeyPlacement(this Microsoft.Extensions.DependencyInjection.IServiceCollection services);Parameters
services Microsoft.Extensions.DependencyInjection.IServiceCollection
The service collection holding the custodian registration.
Returns
IKeyCustodianBuilder
The builder whose placement call completes the wiring.
Remarks
Which custodian holds the keys and how the library uses it are two independent choices, so they are two calls: this one opens the second. Nothing is decided here, and that is the point - a custodian with no placement chosen is a half-wired host, and it fails at startup rather than picking a posture on the host's behalf.
Registered by the backend packages, which know their custodian and nothing about what it will be used for. What the placement calls then do with it belongs to whoever consumes the keys.
ExternalKeysServiceCollectionExtensions.UseKeysInCustodian(this IKeyCustodianBuilder, CustodianHeldKeys) Method
Keeps the private halves OUT of this process entirely: the custodian signs and unwraps, and only public halves are published and used for local signature verification. Every token signed and every encrypted token consumed is a round-trip to the custodian, so throughput is bounded by it - the price of the guarantee that a compromised process yields no key.
public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseKeysInCustodian(this Abblix.Jwt.ExternalKeys.IKeyCustodianBuilder builder, Abblix.Jwt.ExternalKeys.CustodianHeldKeys keys);Parameters
builder IKeyCustodianBuilder
The builder returned by the custodian registration.
keys CustodianHeldKeys
Names the custodian's keys to produce with, and their algorithms.
Returns
Microsoft.Extensions.DependencyInjection.IServiceCollection
The service collection, for chaining.
Remarks
Call this AFTER AddJsonWebTokens(this IServiceCollection). It composes the external signing and decryption backends with their in-process peers, and a composition needs those peers already registered: run first, it would find a one-member family, skip the composite, and leave the external backend to lose the singular resolve to the local one that arrives later.
ExternalKeysServiceCollectionExtensions.UseKeysInCustodian(this IKeyCustodianBuilder, Func<IServiceProvider,CustodianHeldKeys>) Method
Keeps the private halves out of this process, reading the key selection from a service instead of a literal. Suits a host whose key names come from its configuration; a host with literal names uses UseKeysInCustodian(this IKeyCustodianBuilder, CustodianHeldKeys). See that overload for what this placement means and when to call it.
public static Microsoft.Extensions.DependencyInjection.IServiceCollection UseKeysInCustodian(this Abblix.Jwt.ExternalKeys.IKeyCustodianBuilder builder, System.Func<System.IServiceProvider,Abblix.Jwt.ExternalKeys.CustodianHeldKeys> keys);Parameters
builder IKeyCustodianBuilder
The builder returned by the custodian registration.
keys System.Func<System.IServiceProvider,CustodianHeldKeys>
Resolves the key selection from the service provider, once.
Returns
Microsoft.Extensions.DependencyInjection.IServiceCollection
The service collection, for chaining.
Remarks
The selection is a singleton, so the factory runs once per container and the answer is fixed for the life of the process. That rules out anything varying per request or per tenant: a host needing that registers its own key provider rather than varying this.
ExternalKeysServiceCollectionExtensions.UseKeysInProcess(this IKeyCustodianBuilder, MintedKeys) Method
Chooses the placement where the library MINTS its own keys and the custodian only protects them: each key is generated in process, encrypted to the custodian's key-encryption key, shared as ciphertext through IKeyRingStore, and rotated on the policy's schedule. Signing then runs in process, so the custodian is touched once per key rather than once per token.
public static Abblix.Jwt.ExternalKeys.IMintedKeysBuilder UseKeysInProcess(this Abblix.Jwt.ExternalKeys.IKeyCustodianBuilder builder, Abblix.Jwt.ExternalKeys.MintedKeys policy);Parameters
builder IKeyCustodianBuilder
The builder returned by the custodian registration.
policy MintedKeys
What to mint, how often, and which key seals it.
Returns
IMintedKeysBuilder
The builder whose PersistRingTo... call says where the ring lives.
Remarks
This is the weaker posture of the two, which is why it is named rather than defaulted: the private half is unwrapped into process memory and stays there, so a compromised process yields the key itself, not merely the ability to ask the custodian to sign while its credential lives. Use UseKeysInCustodian(this IKeyCustodianBuilder, CustodianHeldKeys) when the key must never be in memory at all.
Call this AFTER AddJsonWebTokens(this IServiceCollection), for the same reason the custodian-held placement does: opening an envelope IS a custodian unwrap, so the external decryption backend has to be composed with its in-process peer, and a composition needs that peer registered first. A store must also be registered for the ring; the backend packages supply one.