JwksKeyResolutionOptions Class
How JWKS-based key resolution finds and refreshes issuers' keys.
public sealed class JwksKeyResolutionOptionsInheritance System.Object → JwksKeyResolutionOptions
Properties
JwksKeyResolutionOptions.CacheLifetime Property
How long a fetched key set answers from cache before the next resolution refetches it. The hot path of validation performs no network I/O within this lifetime - the property the plan demands of the resolver.
public System.TimeSpan CacheLifetime { get; set; }Property Value
JwksKeyResolutionOptions.JwksUris Property
Where a named issuer's JWK Set document is, for issuers known when the host is composed.
public System.Collections.Generic.IDictionary<string,System.Uri> JwksUris { get; }Property Value
System.Collections.Generic.IDictionary<System.String,System.Uri>
Remarks
Consulted first, and additive: two consumers in one host - a back-channel logout receiver and a Shared Signals receiver, say - each add their own issuer without knowing about the other. Nothing here is a slot one consumer can occupy: a single-valued setting makes every consumer past the first compose a chain by hand, and one that forgets to call the previous link silently removes another issuer's keys - a token that used to verify starts failing its signature, which reads as an attack rather than as wiring.
Filled in code, never from a configuration file. An issuer identifier is a URL, and the ':' in it is the configuration hierarchy delimiter - so an entry written in appsettings binds as nested sections and this map stays empty, with no exception and no log. Every issuer then falls through to the well-known convention, which is the same silent wrong-document outcome this map exists to prevent. Environment variables are worse, the '__' delimiter notwithstanding.
Concurrent by construction, because the resolver reads it on the validation path while a host may still be adding to it - a receiver that learns an issuer at run time is exactly the case the selector below describes, and a plain dictionary written during a read is a torn read or a hang rather than an error.
JwksKeyResolutionOptions.RolloverRefetchCooldown Property
The floor between rollover refetches. A token naming a "kid" the cached set lacks forces one refetch - that is how a rotation is noticed before the cache expires - but a flood of tokens with a bogus identifier must not turn that courtesy into hammering the issuer, so within this window the miss answers from cache.
public System.TimeSpan RolloverRefetchCooldown { get; set; }Property Value
JwksKeyResolutionOptions.UseDiscoveryDocument Property
Asks the issuer where its keys are, instead of guessing. When no map entry and no selector answers for an issuer, the resolver reads "jwks_uri" out of that issuer's discovery document at "{issuer}/.well-known/openid-configuration" and fetches the keys from there.
public bool UseDiscoveryDocument { get; set; }Property Value
Remarks
Off by default because it changes where an unconfigured issuer's keys come from, and a host relying on the "{issuer}/.well-known/jwks.json" convention must not have that moved under it by an upgrade.
What it buys is that the location follows the provider. A hand-written jwks_uri is a snapshot, and the copies fail one-sidedly: move the key set at the provider and this receiver refuses every token, while the same application's sign-in keeps working because it re-reads discovery. The log then says the signature does not verify, which reads as a forged token rather than as a configuration value that aged out, and the two places that disagree are never named.
Methods
JwksKeyResolutionOptions.AddJwksUriSelector(Func<string,Uri>) Method
Adds a way to answer where an issuer's JWK Set document is, for issuers whose location is learned at run time. Returning null means "not mine", and resolution carries on.
public Abblix.SecurityEvents.Infrastructure.JwksKeyResolutionOptions AddJwksUriSelector(System.Func<string,System.Uri?> selector);Parameters
selector System.Func<System.String,System.Uri>
Answers for the issuers it knows, null for the rest.
Returns
Remarks
The escape hatch beside JwksUris, for a location that cannot be written down when the host is composed - a Shared Signals transmitter advertises its "jwks_uri" in the ssf-configuration document, and that value, not a convention, is authoritative for it.
Additive for the same reason the map is, and by the same reasoning: two receivers, each learning its own transmitter's metadata, are the ordinary case rather than an exotic one. A settable delegate would make the second one discard the first, and the loss shows up as a signature that stopped verifying.
Answering null rather than throwing is what lets the selectors after it, and then the convention, still run: a delegate that threw for an issuer it did not recognise would take the fallback out for every other issuer, since nothing runs past a throw.