Table of Contents

Configuration reference

Every public options type of the published packages, every setting each one holds, and the value it has when nothing sets it. The page is generated from the compiled code: names, types and defaults are read from the assemblies by reflection — each default from a freshly constructed instance — and the descriptions are the XML documentation the build writes beside them. A test regenerates it on every build and fails when it differs from this file, so it describes the release it ships with.

How to read it:

  • Property is the C# path from the options type you are handed in code, for example AddIdentityServer(options => options.Authentication.CookieLifetime = …).
  • Configuration key is where the configuration binder reads the same setting. These packages bind no configuration themselves: bind the section you choose, as the getting started sample binds IdentityServer. Keys are shown under a section named for the options type. Code only marks a setting the binder cannot read from strings — a certificate, a delegate, a service.
  • Default is the value a new instance holds. Times are d.hh:mm:ss, as configuration writes them. A collection lists what it starts with.

Options types

IdentityServerOptions

Fdyay.IdentityServer.Configuration.IdentityServerOptions in Fdyay.IdentityServer.Core · configured with AddIdentityServer, AddIdentityServerCore · configuration key IdentityServer

Top-level configuration for the identity server.

Property Configuration key Type Default Description
IdentityServerOptions.IssuerUri IdentityServer:IssuerUri string? null The issuer name (URI). If null, it is inferred from the request origin.
IdentityServerOptions.LowerCaseIssuerUri IdentityServer:LowerCaseIssuerUri bool true Whether the lowercase issuer name is emitted. Defaults to true.
IdentityServerOptions.Endpoints IdentityServer:Endpoints EndpointsOptions see EndpointsOptions Endpoint enablement flags.
IdentityServerOptions.Discovery IdentityServer:Discovery DiscoveryOptions see DiscoveryOptions Discovery document options.
IdentityServerOptions.KeyManagement IdentityServer:KeyManagement KeyManagementOptions see KeyManagementOptions Key management options.
IdentityServerOptions.UserInteraction IdentityServer:UserInteraction UserInteractionOptions see UserInteractionOptions User interaction (login/consent) options.
IdentityServerOptions.PushedAuthorization IdentityServer:PushedAuthorization PushedAuthorizationOptions see PushedAuthorizationOptions Pushed authorization request behaviour (RFC 9126).
IdentityServerOptions.Cors IdentityServer:Cors CorsOptions see CorsOptions CORS settings for the protocol endpoints.
IdentityServerOptions.DeviceFlow IdentityServer:DeviceFlow DeviceFlowOptions see DeviceFlowOptions Device authorization grant behaviour (RFC 8628).
IdentityServerOptions.Ciba IdentityServer:Ciba CibaOptions see CibaOptions Back-channel authentication behaviour (OpenID Connect CIBA Core 1.0).
IdentityServerOptions.BackChannelLogout IdentityServer:BackChannelLogout BackChannelLogoutOptions see BackChannelLogoutOptions Back-channel logout notification behaviour (OpenID Connect Back-Channel Logout 1.0).
IdentityServerOptions.MutualTls IdentityServer:MutualTls MutualTlsOptions see MutualTlsOptions Mutual-TLS client authentication and certificate-bound tokens (RFC 8705).
IdentityServerOptions.Events IdentityServer:Events EventsOptions see EventsOptions Which kinds of event reach the sink. All off by default.
IdentityServerOptions.DPoP IdentityServer:DPoP DPoPOptions see DPoPOptions Options for DPoP (RFC 9449).
IdentityServerOptions.InputLengths IdentityServer:InputLengths InputLengthRestrictions see InputLengthRestrictions Bounds on the length of what a caller may send.
IdentityServerOptions.Csp IdentityServer:Csp CspOptions see CspOptions Content-Security-Policy for the pages and iframes this server serves.
IdentityServerOptions.Validation IdentityServer:Validation ValidationOptions see ValidationOptions Checks this server applies to values it has already accepted from a registration.
IdentityServerOptions.PersistentGrants IdentityServer:PersistentGrants PersistentGrantOptions see PersistentGrantOptions What this server does with the grants it persists.
IdentityServerOptions.Authentication IdentityServer:Authentication AuthenticationOptions see AuthenticationOptions The cookies this server writes itself, rather than through a framework handler.
IdentityServerOptions.EmitStaticAudienceClaim IdentityServer:EmitStaticAudienceClaim bool false Whether every access token carries a static aud of {issuer}/resources in addition to the audiences of the API resources it was issued for. Off by default: a static audience every token carries is one every resource server has to be told to ignore.

Backwards compatibility only, for deployments whose APIs were built against an older IdentityServer that emitted this audience unconditionally and validate it. It widens the audience of every token, so leave it off unless a resource server actually requires it.
IdentityServerOptions.EmitIssuerIdentificationResponseParameter IdentityServer:EmitIssuerIdentificationResponseParameter bool true Whether an authorization response carries the iss parameter (RFC 9207). Defaults to true.

The mix-up defence: a client that talks to more than one authorization server cannot otherwise tell which one a redirect came back from, because the response carries a code and a state and nothing that names its author. On by default, which is a deviation worth being deliberate about — RFC 9207 §2 says an authorization server should send it, and OAuth 2.0 requires a client to ignore response parameters it does not recognise, so emitting it cannot break a client that is not looking for it.

Off is for a host that has found the client this does break, and turning it off also stops discovery advertising it: a client told the parameter is there and then not sent it fails the check that was the point of telling it.
IdentityServerOptions.AccessTokenJwtType IdentityServer:AccessTokenJwtType string "at+jwt" The value written to the typ header of JWT access tokens. Defaults to at+jwt, per RFC 9068.

Identity tokens are unaffected and always use JWT. Change this only for a resource server that rejects the RFC 9068 media type; some older stacks expect the bare JWT here.
IdentityServerOptions.LogoutTokenJwtType IdentityServer:LogoutTokenJwtType string "logout+jwt" The value written to the typ header of back-channel logout tokens. Defaults to logout+jwt, per OpenID Connect Back-Channel Logout 1.0 §2.4. Duende's.

Change this only for a relying party that rejects the explicit type. Empty writes the token handler's JWT, where Duende's writes no typ at all. A relying party following the specification may refuse a logout token typed anything else, so the default is the one to keep.
IdentityServerOptions.EmitScopesAsSpaceDelimitedStringInJwt IdentityServer:EmitScopesAsSpaceDelimitedStringInJwt bool true Whether a JWT access token carries scope as one space-delimited string. Defaults to true.

RFC 9068 §2.2.3 says the claim on an at+jwt access token is "a JSON string containing a space-separated list", and IdentityServerOptions.AccessTokenJwtType declares that media type by default — so this is what the token already claims to be doing.

The alternative is not "an array": it is an array or a string depending on how many scopes the client asked for, because the payload builder collapses a single-valued claim to a scalar. A resource server written against a one-scope token reads a string and breaks the day a second scope is added to the client. Off is for a deployment whose resource servers were built against that array and have not been changed yet; it is not a shape this server recommends.

Identity tokens are unaffected: scope is not an identity-token claim.
IdentityServerOptions.ValidateTenantOnAuthorization IdentityServer:ValidateTenantOnAuthorization bool false Whether a session whose tenant claim differs from the request's tenant: hint is sent back to sign in. Defaults to false.

Duende's name, default and rule, measured from its ProcessLoginAsync.
IdentityServerOptions.TokenRequestDefaultScopesFromResourceStore IdentityServer:TokenRequestDefaultScopesFromResourceStore bool false Whether a client_credentials or extension grant token request that names no scope asks for the client's allowed scopes the resource store has, as Duende 8.0.1's does, and is refused when it would be granted none. Defaults to false: the client's allowed scopes as registered, as before.

Duende's TokenRequestValidator.ValidateRequestedScopesAndResourcesAsync, measured. With it, a request naming no scope from a client with no allowed scopes is invalid_scope; client_credentials asks for the API scopes the store has among them (FindApiScopesByNameAsync), so an identity scope such as openid, or a name the store does not have, is left out rather than refused; an extension grant asks for the identity resources and API scopes the store has among them, and offline_access when the client allows offline access, so it gets a refresh token. And a request of either grant granted no scope at all is invalid_scope, as Duende's ResourceValidationResult.Succeeded requires one — a request naming its scopes is otherwise validated as before. Off by default because each changes what an existing client receives: a refusal becomes a token, a token gains a refresh token, or a token becomes a refusal.
IdentityServerOptions.JwtValidationClockSkew IdentityServer:JwtValidationClockSkew TimeSpan 00:00:00 How far past its exp a JWT access token this server issued is still accepted. Defaults to TimeSpan.Zero.

Zero, and the reason is what clock skew is for. A tolerance exists so that two clocks that disagree do not reject each other — but the token being validated here was minted by this server, and read by this server at UserInfo, at introspection and at a local API. There is one clock, so there is nothing to tolerate, and every second of tolerance is a second in which expires_in did not mean what the token response said it meant.

This is a change of behaviour rather than a new knob: nothing set ClockSkew on the validation parameters, so the value in force was IdentityModel's default of five minutes — a token was accepted for five minutes past the expiry this server had published for it, and no setting anywhere said so.

The two places this server validates a JWT minted by somebody else — a client's request object and a client's authentication assertion — deliberately do not read this. There the two clocks are real and a tolerance is what keeps a client with a drifting clock working.
IdentityServerOptions.SupportedRequestObjectSigningAlgorithms IdentityServer:SupportedRequestObjectSigningAlgorithms ICollection<string> [ "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512" ] The signing algorithms a request object (RFC 9101) may use.

Asymmetric only: a request object is a client instructing this server what to do with an authorization request, and it is verified against a key from the client's registration.

Stated rather than inferred, which is the change. Nothing set ValidAlgorithms, so the accepted set was whatever the presented key happened to support — a set no operator could see, narrow, or find written down, and one discovery said nothing about. Discovery now advertises exactly this list, so a client is never told about an algorithm this server would then refuse.
IdentityServerOptions.StrictJarValidation IdentityServer:StrictJarValidation bool false Whether a request object must be typed oauth-authz-req+jwt (RFC 9101 §10.8). Defaults to false.

Duende's, measured from its 8.0.1 package. Not asked of a signed CIBA request, as Duende's CIBA validator does not.
IdentityServerOptions.SupportedClientAssertionSigningAlgorithms IdentityServer:SupportedClientAssertionSigningAlgorithms ICollection<string> [ "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512" ] The signing algorithms a client authentication assertion (RFC 7523) may use.

The same rule at the other door, and the one where it matters more: this assertion is the client's credential. Advertised as token_endpoint_auth_signing_alg_values_supported.
IdentityServerOptions.StrictClientAssertionAudienceValidation IdentityServer:StrictClientAssertionAudienceValidation bool false Whether every private_key_jwt client assertion is held to the strict rule: typed client-authentication+jwt, with exactly one audience, this server's issuer. Defaults to false.

Duende 8.0.1's, measured from its PrivateKeyJwtSecretValidator, after draft-ietf-oauth-rfc7523bis and the audience-injection findings of 2025: an assertion naming several audiences, or a URL as its audience, can be one a client signed for another server. Off, an assertion may name this server's issuer or the URL it was sent to among its audiences, and its typ is not read — except that an assertion typed client-authentication+jwt is held to the strict rule whatever this says, as in Duende. The issuer is compared ignoring one trailing slash, as Duende compares it. New in 0.176.0; until then this server had no such option, and the parity matrix said its rule was unconditionally strict, which it was not.

EndpointsOptions

Fdyay.IdentityServer.Configuration.EndpointsOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.Endpoints · configuration key IdentityServer:Endpoints

Controls which protocol endpoints are enabled.

A disabled endpoint stops serving — the request falls through the identity server middleware — and drops out of the discovery document. Both halves apply: an endpoint that is withdrawn from discovery but still answers is unadvertised rather than off, and so is absent from any surface inventory built from the document.

Property Configuration key Type Default Description
IdentityServerOptions.Endpoints.EnableAuthorizeEndpoint IdentityServer:Endpoints:EnableAuthorizeEndpoint bool true Serves the authorize endpoint at connect/authorize and advertises it as authorization_endpoint. Defaults to true.

While it is on, startup requires an authentication scheme to sign users in with — see UseIdentityServer(); a server that issues only machine tokens can turn it off instead.
IdentityServerOptions.Endpoints.EnableTokenEndpoint IdentityServer:Endpoints:EnableTokenEndpoint bool true Serves the token endpoint at connect/token and advertises it as token_endpoint. Defaults to true.
IdentityServerOptions.Endpoints.EnableUserInfoEndpoint IdentityServer:Endpoints:EnableUserInfoEndpoint bool true Serves the UserInfo endpoint at connect/userinfo and advertises it as userinfo_endpoint. Defaults to true.
IdentityServerOptions.Endpoints.EnableDiscoveryEndpoint IdentityServer:Endpoints:EnableDiscoveryEndpoint bool true Serves the discovery document. Also governs the JWKS endpoint, which has no separate flag.
IdentityServerOptions.Endpoints.EnableOAuth2MetadataEndpoint IdentityServer:Endpoints:EnableOAuth2MetadataEndpoint bool true Serves the OAuth 2.0 authorization server metadata (RFC 8414) at /.well-known/oauth-authorization-server: the discovery document, for a client that reads OAuth's well-known path rather than OpenID Connect's. Defaults to true, as in Duende.

Independent of EndpointsOptions.EnableDiscoveryEndpoint, as Duende's is.
IdentityServerOptions.Endpoints.EnableJwtRequestUri IdentityServer:Endpoints:EnableJwtRequestUri bool false Whether this server will fetch a JAR (RFC 9101) request object from a request_uri the client hosts. Defaults to false.

Off by default because it is an outbound request to a location the client chooses: an authorization request naming an internal address would have this server fetch it. Request objects sent by value in request need no such fetch and are always accepted.

Unrelated to the request_uri of PAR (RFC 9126), which is an opaque reference this server issued and is always on. The two are told apart by PAR's registered URN prefix.
IdentityServerOptions.Endpoints.EnableEndSessionEndpoint IdentityServer:Endpoints:EnableEndSessionEndpoint bool true Serves the end-session (RP-initiated signout) endpoint at connect/endsession and advertises it as end_session_endpoint. Defaults to true.
IdentityServerOptions.Endpoints.EnableCheckSessionEndpoint IdentityServer:Endpoints:EnableCheckSessionEndpoint bool true Serves the check-session iframe of OpenID Connect Session Management 1.0, and governs whether the document advertises check_session_iframe.
IdentityServerOptions.Endpoints.EnableTokenRevocationEndpoint IdentityServer:Endpoints:EnableTokenRevocationEndpoint bool true Serves the token revocation endpoint (RFC 7009) at connect/revocation and advertises it as revocation_endpoint. Defaults to true.
IdentityServerOptions.Endpoints.EnableIntrospectionEndpoint IdentityServer:Endpoints:EnableIntrospectionEndpoint bool true Serves the token introspection endpoint (RFC 7662) at connect/introspect and advertises it as introspection_endpoint. Defaults to true.
IdentityServerOptions.Endpoints.EnablePushedAuthorizationEndpoint IdentityServer:Endpoints:EnablePushedAuthorizationEndpoint bool true Serves the pushed authorization request endpoint (RFC 9126) at connect/par and advertises it as pushed_authorization_request_endpoint. Defaults to true.

Turning it off while PushedAuthorization.Required is true is refused at startup, because no client could then obtain the request_uri every authorization request would need.
IdentityServerOptions.Endpoints.EnableDeviceAuthorizationEndpoint IdentityServer:Endpoints:EnableDeviceAuthorizationEndpoint bool true Serves the device authorization endpoint (RFC 8628) at connect/deviceauthorization and advertises it as device_authorization_endpoint. Defaults to true.
IdentityServerOptions.Endpoints.EnableBackchannelAuthenticationEndpoint IdentityServer:Endpoints:EnableBackchannelAuthenticationEndpoint bool false Serves the backchannel authentication endpoint of OpenID Connect CIBA Core 1.0. Defaults to false — the only endpoint here that does.

Every other endpoint can answer a request with what this library alone knows. This one cannot: a backchannel request names a user who is not present, so serving it needs a host-supplied way to resolve that name (IBackchannelAuthenticationUserValidator) and a host-supplied way to reach the person behind it (IBackchannelAuthenticationUserNotificationService). On by default would mean a discovery document advertising an endpoint that answers every request with a 500, for every host that upgraded without asking for CIBA.

Turning it on without registering both is refused at startup rather than discovered on the first request — see UseIdentityServer().
IdentityServerOptions.Endpoints.EnableSamlSigninEndpoint IdentityServer:Endpoints:EnableSamlSigninEndpoint bool false Serves the SAML 2.0 single sign-on endpoint, and the IdP-initiated door beneath it. Defaults to false, as Duende's does; AddSaml switches it on.

The four SAML switches are off here because the endpoints they govern exist only once AddSaml registers them, and AddSaml turns all four on with a Configure<IdentityServerOptions> of its own — Duende's arrangement, measured. A host switching one off configures after AddSaml, so its setting is applied last.
IdentityServerOptions.Endpoints.EnableSamlSigninCallbackEndpoint IdentityServer:Endpoints:EnableSamlSigninCallbackEndpoint bool false Serves the SAML 2.0 sign-in callback, where the browser comes back from the login page to have its sign-on answered. Defaults to false, as Duende's does; AddSaml switches it on.
IdentityServerOptions.Endpoints.EnableSamlLogoutEndpoint IdentityServer:Endpoints:EnableSamlLogoutEndpoint bool false Serves the SAML 2.0 single logout endpoint. Defaults to false, as Duende's does; AddSaml switches it on.
IdentityServerOptions.Endpoints.EnableSamlMetadataEndpoint IdentityServer:Endpoints:EnableSamlMetadataEndpoint bool false Serves the SAML 2.0 metadata document. Defaults to false, as Duende's does; AddSaml switches it on.

DiscoveryOptions

Fdyay.IdentityServer.Configuration.DiscoveryOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.Discovery · configuration key IdentityServer:Discovery

Controls what is emitted in the discovery document.

Property Configuration key Type Default Description
IdentityServerOptions.Discovery.ShowEndpoints IdentityServer:Discovery:ShowEndpoints bool true Whether discovery lists the endpoint URLs (authorization_endpoint, token_endpoint and the rest) and the members that describe them, such as request_parameter_supported. On by default.

Only enabled endpoints are listed either way; see EndpointsOptions.
IdentityServerOptions.Discovery.ShowKeySet IdentityServer:Discovery:ShowKeySet bool true Whether discovery lists jwks_uri and the key set is served there. Duende's; on by default.

Until 0.139.0 the key set was served with this off, at a path the document no longer named.
IdentityServerOptions.Discovery.ShowIdentityScopes IdentityServer:Discovery:ShowIdentityScopes bool true Whether scopes_supported includes the enabled identity resources marked to show in discovery. On by default.
IdentityServerOptions.Discovery.ShowApiScopes IdentityServer:Discovery:ShowApiScopes bool true Whether scopes_supported includes the enabled API scopes marked to show in discovery, plus offline_access. On by default.
IdentityServerOptions.Discovery.ShowClaims IdentityServer:Discovery:ShowClaims bool true Whether discovery lists claims_supported: the user claims of every enabled identity resource, API resource and API scope. On by default.
IdentityServerOptions.Discovery.ShowResponseTypes IdentityServer:Discovery:ShowResponseTypes bool true Whether discovery lists response_types_supported, which is code only. On by default.
IdentityServerOptions.Discovery.ShowResponseModes IdentityServer:Discovery:ShowResponseModes bool true Whether discovery lists response_modes_supported. Duende's; on by default.

Until 0.130.0 the list went with DiscoveryOptions.ShowResponseTypes; Duende has a switch of its own for it.
IdentityServerOptions.Discovery.ShowGrantTypes IdentityServer:Discovery:ShowGrantTypes bool true Whether discovery lists grant_types_supported: the built-in grants, less CIBA while its endpoint is off, and the host's extension grants when DiscoveryOptions.ShowExtensionGrantTypes is on. On by default.
IdentityServerOptions.Discovery.ShowExtensionGrantTypes IdentityServer:Discovery:ShowExtensionGrantTypes bool true Whether grant_types_supported lists the extension grants a host registered. Duende's; on by default.
IdentityServerOptions.Discovery.ShowTokenEndpointAuthenticationMethods IdentityServer:Discovery:ShowTokenEndpointAuthenticationMethods bool true Whether discovery lists token_endpoint_auth_methods_supported, and beside it the client-assertion algorithms when private_key_jwt is one of them. Duende's; on by default.
IdentityServerOptions.Discovery.ShowRevocationEndpointAuthenticationMethods IdentityServer:Discovery:ShowRevocationEndpointAuthenticationMethods bool true Whether discovery lists revocation_endpoint_auth_methods_supported (RFC 8414 §2), and its algorithms as for DiscoveryOptions.ShowTokenEndpointAuthenticationMethods. Duende's; on by default.
IdentityServerOptions.Discovery.ShowIntrospectionEndpointAuthenticationMethods IdentityServer:Discovery:ShowIntrospectionEndpointAuthenticationMethods bool true Whether discovery lists introspection_endpoint_auth_methods_supported (RFC 8414 §2), and its algorithms as for DiscoveryOptions.ShowTokenEndpointAuthenticationMethods. Duende's; on by default.
IdentityServerOptions.Discovery.ExpandRelativePathsInCustomEntries IdentityServer:Discovery:ExpandRelativePathsInCustomEntries bool true Whether a DiscoveryOptions.CustomEntries string starting ~/ is expanded to a URL under the issuer. Duende's; on by default.
IdentityServerOptions.Discovery.ResponseCacheInterval IdentityServer:Discovery:ResponseCacheInterval int? null The max-age, in seconds, of the discovery document's and the key set's Cache-Control header; zero sends no-store. Duende's; null by default, which sends no Cache-Control header.
IdentityServerOptions.Discovery.EnableDiscoveryDocumentCache IdentityServer:Discovery:EnableDiscoveryDocumentCache bool false Whether the discovery document is kept in the IDistributedCache. Duende's; off by default.
IdentityServerOptions.Discovery.DiscoveryDocumentCacheDuration IdentityServer:Discovery:DiscoveryDocumentCacheDuration TimeSpan 00:01:00 How long a cached discovery document is served. Duende's; 1 minute by default.
IdentityServerOptions.Discovery.CustomEntries IdentityServer:Discovery:CustomEntries Dictionary<string, object> { } Members added to the discovery document after its own; one the document already has is not replaced. Duende's.

KeyManagementOptions

Fdyay.IdentityServer.Configuration.KeyManagementOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.KeyManagement · configuration key IdentityServer:KeyManagement

Automatic signing-key management options.

Property Configuration key Type Default Description
IdentityServerOptions.KeyManagement.Enabled IdentityServer:KeyManagement:Enabled bool true Whether automatic key management is enabled. Defaults to true.
IdentityServerOptions.KeyManagement.RotationInterval IdentityServer:KeyManagement:RotationInterval TimeSpan 90.00:00:00 How long a key is used for signing before rotation. Defaults to 90 days.
IdentityServerOptions.KeyManagement.PropagationTime IdentityServer:KeyManagement:PropagationTime TimeSpan 14.00:00:00 How long before rotation a new key is announced. Defaults to 14 days.
IdentityServerOptions.KeyManagement.RetentionDuration IdentityServer:KeyManagement:RetentionDuration TimeSpan 14.00:00:00 How long a retired key remains published in the JWKS. Defaults to 14 days.
IdentityServerOptions.KeyManagement.KeyCacheDuration IdentityServer:KeyManagement:KeyCacheDuration TimeSpan 1.00:00:00 How long loaded key material is cached in memory. Defaults to 24 hours.

Held to at most half of KeyManagementOptions.PropagationTime, as Duende holds it, so a new key is seen well before it signs.
IdentityServerOptions.KeyManagement.InitializationDuration IdentityServer:KeyManagement:InitializationDuration TimeSpan 00:05:00 How long after the first key is created every instance treats the key set as new. Defaults to 5 minutes, as Duende's does; zero turns the initialisation window off.

Duende 8.0.1's, measured. While every key in the store is this young, an instance that has just created one waits KeyManagementOptions.InitializationSynchronizationDelay and reads the store again, so that instances starting together on one store see each other's keys, and caches the set for KeyManagementOptions.InitializationKeyCacheDuration rather than KeyManagementOptions.KeyCacheDuration. With the oldest current key signing, they converge on one.
IdentityServerOptions.KeyManagement.InitializationSynchronizationDelay IdentityServer:KeyManagement:InitializationSynchronizationDelay TimeSpan 00:00:05 How long an instance that created a key during the initialisation window waits before reading the store again. Defaults to 5 seconds, as Duende's does.

Not waited for on the in-memory store, which no other instance can share: there is nobody's key to wait for. Duende has no in-memory store.
IdentityServerOptions.KeyManagement.InitializationKeyCacheDuration IdentityServer:KeyManagement:InitializationKeyCacheDuration TimeSpan 00:01:00 How long the key set is cached while every key is within the initialisation window. Defaults to 1 minute, as Duende's does.
IdentityServerOptions.KeyManagement.DeleteRetiredKeys IdentityServer:KeyManagement:DeleteRetiredKeys bool true Whether a key past KeyManagementOptions.KeyRetirementAge is deleted from the store. Defaults to true, as Duende's does.

Off, a retired key stays in the store and is neither published nor used.
IdentityServerOptions.KeyManagement.RsaKeySize IdentityServer:KeyManagement:RsaKeySize int 2048 The RSA key size in bits for generated keys. Defaults to 2048.
IdentityServerOptions.KeyManagement.SigningAlgorithms IdentityServer:KeyManagement:SigningAlgorithms ICollection<SigningAlgorithmOptions> [ ] The algorithms a key is kept for, one current key each; the first signs when a client or resource names none. Empty by default, which is RS256 alone, as Duende's is.

Duende 8.0.1's, measured: RS256/384/512, PS256/384/512 and ES256/384/512, each at most once, and SigningAlgorithmOptions.UseX509Certificate for the RSA families only. Until 0.137.0 this was SigningAlgorithm, a single RSA algorithm.
IdentityServerOptions.KeyManagement.AllowedSigningAlgorithmNames IdentityServer:KeyManagement:AllowedSigningAlgorithmNames IEnumerable<string> [ "RS256" ] The names of KeyManagementOptions.SigningAlgorithms, else RS256.
IdentityServerOptions.KeyManagement.KeyPath IdentityServer:KeyManagement:KeyPath string "{working directory}/keys" Where the default key store writes keys. Defaults to a keys directory under the working directory, as Duende's does.

Read by the default FileSystemKeyStore; a host that registers its own store ignores it.
IdentityServerOptions.KeyManagement.DataProtectKeys IdentityServer:KeyManagement:DataProtectKeys bool true Whether a key is protected with ASP.NET Core Data Protection before it is stored. Defaults to true, as Duende's does.

Off, the private key is stored as it is; for a store that protects what it holds by other means.

SigningAlgorithmOptions

Fdyay.IdentityServer.Configuration.SigningAlgorithmOptions in Fdyay.IdentityServer.Core · each item of IdentityServerOptions.KeyManagement.SigningAlgorithms[i] · configuration key IdentityServer:KeyManagement:SigningAlgorithms:{index}

An algorithm automatic key management keeps a key for. Duende's SigningAlgorithmOptions.

An item has no parameterless constructor, so there is no default to read: each is set where it is created.

Property Configuration key Type Default Description
IdentityServerOptions.KeyManagement.SigningAlgorithms[i].Name IdentityServer:KeyManagement:SigningAlgorithms:{index}:Name string — The algorithm, e.g. RS256, PS384, ES256.
IdentityServerOptions.KeyManagement.SigningAlgorithms[i].UseX509Certificate IdentityServer:KeyManagement:SigningAlgorithms:{index}:UseX509Certificate bool — Whether the key is wrapped in a self-signed certificate, published as x5c and x5t. RSA only, as Duende's is.

UserInteractionOptions

Fdyay.IdentityServer.Configuration.UserInteractionOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.UserInteraction · configuration key IdentityServer:UserInteraction

Paths the protocol endpoints redirect to for interactive login, consent and signout.

Property Configuration key Type Default Description
IdentityServerOptions.UserInteraction.LoginUrl IdentityServer:UserInteraction:LoginUrl string "/account/login" The login page path. Defaults to /account/login.
IdentityServerOptions.UserInteraction.ConsentUrl IdentityServer:UserInteraction:ConsentUrl string "/account/consent" The consent page path. Defaults to /account/consent.
IdentityServerOptions.UserInteraction.LogoutUrl IdentityServer:UserInteraction:LogoutUrl string "/account/logout" The logout page path. Defaults to /account/logout.
IdentityServerOptions.UserInteraction.ErrorUrl IdentityServer:UserInteraction:ErrorUrl string "/account/error" The error page path. Defaults to /account/error.
IdentityServerOptions.UserInteraction.ReturnUrlParameter IdentityServer:UserInteraction:ReturnUrlParameter string "returnUrl" A second name the login page also accepts a return URL under. Defaults to returnUrl.

No longer emitted by anything. Until 0.56.0 the SAML single sign-on endpoint used this while the authorize endpoint used UserInteractionOptions.LoginReturnUrlParameter — two names for one destination, which is how a host that renamed the documented one broke SAML sign-on while OIDC kept working. Both redirects now emit UserInteractionOptions.LoginReturnUrlParameter.

Kept, and still read, so a host that had configured only this one is not broken by the unification: the login page tries UserInteractionOptions.LoginReturnUrlParameter first and falls back to this. Prefer the specific one. The same shape as 0.52.0's NameIdClaimType fix — one side owns the canonical spelling and the other is an additional mapping rather than a replacement.
IdentityServerOptions.UserInteraction.LoginReturnUrlParameter IdentityServer:UserInteraction:LoginReturnUrlParameter string "returnUrl" The return-url query parameter name for the login redirect. Defaults to returnUrl.

Separate from the consent parameter so a host can route the two redirects differently.
IdentityServerOptions.UserInteraction.ConsentReturnUrlParameter IdentityServer:UserInteraction:ConsentReturnUrlParameter string "returnUrl" The return-url query parameter name for the consent redirect. Defaults to returnUrl.

Separate from the login parameter so a host can route the two redirects differently.
IdentityServerOptions.UserInteraction.CreateAccountUrl IdentityServer:UserInteraction:CreateAccountUrl string? null The create-account page, for a request with prompt=create. Defaults to null. Duende's.

Duende 8.0.1's, measured: unset, create is not among the supported prompt values and a request asking for it is refused as an unsupported prompt; set, UseIdentityServer adds create to UserInteractionOptions.PromptValuesSupported, so discovery publishes it and the authorize endpoint sends such a request here.
IdentityServerOptions.UserInteraction.CreateAccountReturnUrlParameter IdentityServer:UserInteraction:CreateAccountReturnUrlParameter string "returnUrl" The return-url query parameter name for the create-account redirect. Defaults to returnUrl. Duende's.
IdentityServerOptions.UserInteraction.CustomRedirectReturnUrlParameter IdentityServer:UserInteraction:CustomRedirectReturnUrlParameter string "returnUrl" The return-url query parameter name for a redirect an interaction generator asks for. Defaults to returnUrl. Duende's.

Appended to InteractionResponse.RedirectUrl when a host's IAuthorizeInteractionResponseGenerator sends the user somewhere of its own before the request is answered.
IdentityServerOptions.UserInteraction.PromptValuesSupported IdentityServer:UserInteraction:PromptValuesSupported ICollection<string> [ "none", "login", "consent", "select_account" ] The prompt values the authorize endpoint accepts, published as prompt_values_supported. Duende's.

Duende 8.0.1's, measured: none, login, consent and select_account, with create added at startup when UserInteractionOptions.CreateAccountUrl is set. A request carrying any other value is refused (invalid_request, "Unsupported prompt mode"); until 0.142.0 an unknown value was accepted and ignored. A value added here needs an IAuthorizeInteractionResponseGenerator that acts on it.
IdentityServerOptions.UserInteraction.AllowOriginInReturnUrl IdentityServer:UserInteraction:AllowOriginInReturnUrl bool false Whether a return URL may be absolute when it names this server's own origin. Defaults to false. Duende's.

Duende 8.0.1's, measured: read by the OpenID Connect and SAML return-URL parsers, which take this server's origin off the front of an absolute return URL — compared ignoring case — and then judge what is left as they judge any other.

Ours, decided 2026-10-14: it also decides whether an interaction page configured as an absolute URL is handed an absolute return URL. Duende hands one whatever the option, so a page on this server written that way stops resuming requests until the option is on; here, off, every page is handed the relative return URL it always was.
IdentityServerOptions.UserInteraction.LogoutIdParameter IdentityServer:UserInteraction:LogoutIdParameter string "logoutId" The logout-id query parameter name. Defaults to logoutId.
IdentityServerOptions.UserInteraction.ErrorIdParameter IdentityServer:UserInteraction:ErrorIdParameter string "errorId" The error-id query parameter name. Defaults to errorId.
IdentityServerOptions.UserInteraction.ShowErrorDetail IdentityServer:UserInteraction:ShowErrorDetail bool false Whether the error page may show the error code, description and requested client id. Defaults to false.

Off by default so a host that configures nothing discloses nothing: end users see a generic message and the reference id only. Turn it on in environments where showing protocol detail to whoever hit the page is acceptable.
IdentityServerOptions.UserInteraction.ErrorMessageLifetime IdentityServer:UserInteraction:ErrorMessageLifetime TimeSpan 00:05:00 How long a stored error context can be read back. Defaults to 5 minutes.

Long enough for the redirect to the error page, short enough not to accumulate.
IdentityServerOptions.UserInteraction.ConsentMessageLifetime IdentityServer:UserInteraction:ConsentMessageLifetime TimeSpan 00:05:00 How long a recorded consent decision can be read back. Defaults to 5 minutes.

Long enough for the redirect from the consent page back to the authorize endpoint, and no longer.

PushedAuthorizationOptions

Fdyay.IdentityServer.Configuration.PushedAuthorizationOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.PushedAuthorization · configuration key IdentityServer:PushedAuthorization

Server-wide settings for pushed authorization requests.

Property Configuration key Type Default Description
IdentityServerOptions.PushedAuthorization.Lifetime IdentityServer:PushedAuthorization:Lifetime TimeSpan 00:10:00 How long a pushed request stays redeemable. Defaults to ten minutes.

Short by design: the window only has to cover the redirect from the client to the browser and on to the authorize endpoint, and a reference value is a bearer credential for the whole request while it lives. A client may shorten it further per request; it may not lengthen it past this.
IdentityServerOptions.PushedAuthorization.Required IdentityServer:PushedAuthorization:Required bool false Whether every client must push its authorization requests. Defaults to false.

Individual clients can require it on their own with Client.RequirePushedAuthorization; this makes it server-wide, which is what an installation with no legacy clients left should do.
IdentityServerOptions.PushedAuthorization.AllowUnregisteredPushedRedirectUris IdentityServer:PushedAuthorization:AllowUnregisteredPushedRedirectUris bool false Whether a confidential client's pushed request may name a redirect URI it did not register. Defaults to false.

Duende's, measured from its 8.0.1 package (RFC 9126 §2.4): a client that authenticated to push has proved who it is, so the redirect URI it pushes is its own word rather than a browser's. Only a client with RequireClientSecret, only for a pushed request and its redemption, and such a client then needs no registered redirect URI at all.

CorsOptions

Fdyay.IdentityServer.Configuration.CorsOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.Cors · configuration key IdentityServer:Cors

CORS settings for the protocol endpoints.

Property Configuration key Type Default Description
IdentityServerOptions.Cors.CorsPaths IdentityServer:Cors:CorsPaths ICollection<string> [ ".well-known/openid-configuration", ".well-known/openid-configuration/jwks", "connect/userinfo", "connect/token", "connect/revocation" ] The protocol endpoint paths CORS is applied to, relative and without a leading slash.

Defaults to the endpoints a browser-based client calls directly: discovery and its key set, user info, token and revocation. Authorize and end session are absent because a browser reaches them by navigation rather than by script, and introspection because it is a resource server's call, not a browser's. These are the values in ProtocolRoutePaths. They are spelled out here because the paths live in the hosting assembly and these options do not depend on it; a test asserts the two agree.
IdentityServerOptions.Cors.CorsPolicyName IdentityServer:Cors:CorsPolicyName string "IdentityServer" The name of the ASP.NET Core CORS policy evaluated for protocol endpoint requests.

The policy decides which origins are allowed by asking the registered ICorsPolicyService. Register a different implementation of that to change the answer, rather than redefining a policy under this name.
IdentityServerOptions.Cors.PreflightCacheDuration IdentityServer:Cors:PreflightCacheDuration TimeSpan? null The Access-Control-Max-Age value sent on preflight responses.

Null by default, which emits no header and leaves the preflight cache duration to the browser.

DeviceFlowOptions

Fdyay.IdentityServer.Configuration.DeviceFlowOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.DeviceFlow · configuration key IdentityServer:DeviceFlow

Settings for the device authorization grant (RFC 8628).

Property Configuration key Type Default Description
IdentityServerOptions.DeviceFlow.Lifetime IdentityServer:DeviceFlow:Lifetime int 300 How long the user has to approve a device, in seconds. Defaults to 5 minutes.

Long enough to walk to another device and type a code, short enough that an abandoned request stops being approvable soon after the user has forgotten about it.
IdentityServerOptions.DeviceFlow.DefaultUserCodeType IdentityServer:DeviceFlow:DefaultUserCodeType string "Readable" The IUserCodeGenerator.UserCodeType used for a client that names none. Defaults to UserCodeTypes.Readable.

Duende defaults to its nine-digit numeric code, about 30 bits; this server's default has been the twelve character readable one, a little over 51, since 0.23.0, and stays so — a user code names a pending authorization to anybody who guesses it, so the weaker form is opted into per client or here, not inherited.
IdentityServerOptions.DeviceFlow.Interval IdentityServer:DeviceFlow:Interval int 5 The minimum seconds a device should wait between polls. Defaults to 5.

Returned as interval, and enforced: polling faster is answered with slow_down.
IdentityServerOptions.DeviceFlow.VerificationUrl IdentityServer:DeviceFlow:VerificationUrl string "/device" The path the user is sent to in order to enter their code. Defaults to /device.
IdentityServerOptions.DeviceFlow.UserCodeParameter IdentityServer:DeviceFlow:UserCodeParameter string "userCode" The query parameter carrying the user code on the verification URL. Defaults to userCode.

Used to build verification_uri_complete, which a device can render as a QR code.

CibaOptions

Fdyay.IdentityServer.Configuration.CibaOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.Ciba · configuration key IdentityServer:Ciba

Settings for backchannel authentication (OpenID Connect CIBA Core 1.0).

Nothing here names a delivery mode: which one a client gets is its registration's BackChannelTokenDeliveryMode, and all three are delivered — poll since 0.27.0, ping since 0.72.0 and push since 0.73.0. What is server-wide is how long a callback may take, and whether this host checks user codes.

Property Configuration key Type Default Description
IdentityServerOptions.Ciba.Lifetime IdentityServer:Ciba:Lifetime int 300 How long a user has to answer a request, in seconds. Defaults to 5 minutes.

Longer than a device code's window would be, and for the opposite reason: the user is not standing at a screen waiting to type something, they are being interrupted. Short enough that a request nobody answered stops being answerable while the person who triggered it still remembers it.
IdentityServerOptions.Ciba.MaximumLifetime IdentityServer:Ciba:MaximumLifetime int 600 The longest lifetime a client may ask for with requested_expiry. Defaults to 10 minutes.

A ceiling rather than a second default: CibaOptions.Lifetime is what a client that asks for nothing gets, and this is as far as one that asks may go. Without the cap a client chooses how long an unanswered request stays approvable, which is not the client's decision to make.
IdentityServerOptions.Ciba.Interval IdentityServer:Ciba:Interval int 5 The minimum seconds a client should wait between polls. Defaults to 5.

Returned as interval, and enforced: polling faster is answered with slow_down. A client may be given a longer one of its own with Client.PollingInterval.
IdentityServerOptions.Ciba.NotificationTimeout IdentityServer:Ciba:NotificationTimeout TimeSpan 00:00:10 How long to wait for a client's ping notification endpoint. Defaults to 10 seconds.

Ten seconds because that is what every other outbound hop in this tree waits — the back-channel logout notification, the JAR request_uri fetch, a client-credentials token request — and for the reason they give: somebody is waiting on the answer.

Here that somebody is the user, which is easy to miss. The notification is sent while recording their decision, so their "approve" does not come back until the client's endpoint has answered or this elapses. A generous value would let a client that registered for ping and then stopped answering hold up the person approving its requests.

For a ping, elapsing loses nothing but the callback: the answer is recorded first and stays redeemable by polling, and the failure is raised as BackChannelAuthenticationNotificationFailureEvent. For a push it loses the tokens, which were minted to travel in the callback and which the client may not poll for — the same event records it, and that is the trade a client makes by registering for push.
IdentityServerOptions.Ciba.UserCodeParameterSupported IdentityServer:Ciba:UserCodeParameterSupported bool false Whether this host's IBackchannelAuthenticationUserValidator checks a user_code. Defaults to false.

This server cannot check a user code — it is a secret between the user and the host — so this is the host declaring that its validator does. It decides what discovery says (backchannel_user_code_parameter_supported) and whether a request carrying a user_code is accepted. Off, one is refused rather than ignored: a client that collected a PIN from somebody and sent it believes the PIN gates the request, and accepting it with nothing checking would make that belief false while every response looked right. Duende has no such option; this is the difference.

BackChannelLogoutOptions

Fdyay.IdentityServer.Configuration.BackChannelLogoutOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.BackChannelLogout · configuration key IdentityServer:BackChannelLogout

Back-channel logout notification behaviour (OpenID Connect Back-Channel Logout 1.0).

Property Configuration key Type Default Description
IdentityServerOptions.BackChannelLogout.Timeout IdentityServer:BackChannelLogout:Timeout TimeSpan 00:00:10 How long to wait for one relying party's logout endpoint before giving up on it.

Per relying party, not for the whole fan-out. Sign-out must not be held open by a client that has gone away, and the user is waiting on the response, so this is deliberately short.
IdentityServerOptions.BackChannelLogout.LogoutTokenLifetime IdentityServer:BackChannelLogout:LogoutTokenLifetime int 300 Lifetime of an issued logout token, in seconds.

The token is delivered directly to the relying party and consumed immediately, so this only has to cover clock skew and the request itself.

MutualTlsOptions

Fdyay.IdentityServer.Configuration.MutualTlsOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.MutualTls · configuration key IdentityServer:MutualTls

Mutual-TLS client authentication and certificate-bound access tokens (RFC 8705).

Property Configuration key Type Default Description
IdentityServerOptions.MutualTls.ClientCertificateAuthenticationScheme IdentityServer:MutualTls:ClientCertificateAuthenticationScheme string "Certificate" The authentication scheme that must accept the client certificate before an mTLS alias is served. Defaults to Certificate, the name ASP.NET Core's certificate handler registers under, as Duende's does.

Duende 8.0.1's, measured: a request to a connect/mtls/ alias is authenticated with this scheme first, and one it does not accept is refused with invalid_client before any endpoint runs. The handler — typically AddAuthentication().AddCertificate() — is where the chain, revocation and allowed issuers are checked; the client's registered thumbprint or name is still compared afterwards, as before.
IdentityServerOptions.MutualTls.Enabled IdentityServer:MutualTls:Enabled bool false Whether the protocol endpoints are also served under connect/mtls/. Defaults to false.

The aliases exist so that client certificates can be required on those paths without requiring them everywhere: a TLS listener asks for a certificate per host or per path, and asking for one at the authorize endpoint would prompt every browser user for a certificate they do not have. Turning this on only publishes the paths — the host still has to configure its listener to request a certificate there.

The aliases are path-based only. A subdomain form exists in the wider ecosystem and is deliberately not offered here: nothing in these options names a domain, so no configuration promises one.
IdentityServerOptions.MutualTls.AlwaysEmitConfirmationClaim IdentityServer:MutualTls:AlwaysEmitConfirmationClaim bool false Whether a token gets a cnf claim whenever the connection carried a client certificate, even if the client authenticated some other way. Defaults to false.

Off by default because the certificate that authenticated the client is the one the client has committed to using, while a certificate that merely happened to be on the connection is not: binding a token to it makes every later call fail unless the client presents that same certificate again.

EventsOptions

Fdyay.IdentityServer.Configuration.EventsOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.Events · configuration key IdentityServer:Events

Which kinds of event reach the sink.

Every flag defaults to false. Events carry client ids, subject ids and addresses, and where they end up is the host's decision rather than this server's — so raising them is opt-in, and a host that never configures a sink never emits anything anywhere.

The four are separate because they are wanted separately: a deployment that wants an alert on EventTypes.Error almost never wants a record of every successful token issuance, and one doing security monitoring wants EventTypes.Failure and nothing else.

Property Configuration key Type Default Description
IdentityServerOptions.Events.RaiseSuccessEvents IdentityServer:Events:RaiseSuccessEvents bool false Raise events for operations that succeeded.
IdentityServerOptions.Events.RaiseFailureEvents IdentityServer:Events:RaiseFailureEvents bool false Raise events for requests the server refused.
IdentityServerOptions.Events.RaiseInformationEvents IdentityServer:Events:RaiseInformationEvents bool false Raise events that are neither a success nor a refusal.
IdentityServerOptions.Events.RaiseErrorEvents IdentityServer:Events:RaiseErrorEvents bool false Raise events for faults in the server itself.
IdentityServerOptions.Events.IncludeStackTraceInUnhandledExceptionEvents IdentityServer:Events:IncludeStackTraceInUnhandledExceptionEvents bool false Put the exception's stack trace, and its inner exceptions, in UnhandledExceptionEvent.Details. Off by default.

Off, Details carries the exception's type and message. On, it carries Exception.ToString(), which is what Duende 8.0.1's always carries. A stack trace names this server's internals and sometimes the values it was working on, so it is the host's decision, made knowing where its sink sends things (the decision of 2026-10-13). Not Duende's: Duende has no switch, because it has no default without the stack.

DPoPOptions

Fdyay.IdentityServer.Configuration.DPoPOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.DPoP · configuration key IdentityServer:DPoP

Options for DPoP proof validation (RFC 9449).

The other way to sender-constrain a token, and the one a client with no certificate can use. mTLS binds to something the transport already proved; DPoP binds to a key the client proves per request, which is why these options are almost entirely about time — a proof is only worth anything for as long as it cannot be replayed.

Property Configuration key Type Default Description
IdentityServerOptions.DPoP.ProofTokenValidityDuration IdentityServer:DPoP:ProofTokenValidityDuration TimeSpan 00:01:00 How long a proof stays acceptable after the iat it carries. Defaults to one minute.

The window in which a stolen proof still works, so it wants to be short. It is not the only thing stopping a replay — every jti is remembered for at least this long — but it is what bounds how much has to be remembered.
IdentityServerOptions.DPoP.ClientClockSkew IdentityServer:DPoP:ClientClockSkew TimeSpan 00:05:00 How far a client's clock may run ahead of this server's. Defaults to five minutes.

Separate from the validity window because they answer different questions: the window is how long a proof lives, this is how wrong the client's idea of "now" may be. Folding them together would mean tolerating a skewed clock by keeping every proof alive longer, for every client.
IdentityServerOptions.DPoP.ServerClockSkew IdentityServer:DPoP:ServerClockSkew TimeSpan 00:00:00 How far the servers in a farm may disagree about the time when a DPoP nonce one of them issued is checked by another. Defaults to zero, as in Duende.

A nonce is accepted for DPoPOptions.ProofTokenValidityDuration after it was issued, plus this.
IdentityServerOptions.DPoP.SupportedSigningAlgorithms IdentityServer:DPoP:SupportedSigningAlgorithms ICollection<string> [ "RS256", "RS384", "RS512", "PS256", "PS384", "PS512", "ES256", "ES384", "ES512" ] The signing algorithms a proof may use.

Asymmetric only, and stated rather than inferred: a proof is a signature by a key the client embeds in the proof itself, so accepting a symmetric algorithm would accept a proof signed by a key the attacker chose. Discovery advertises exactly this list, so a client is never told about an algorithm this server would then refuse.

InputLengthRestrictions

Fdyay.IdentityServer.Configuration.InputLengthRestrictions in Fdyay.IdentityServer.Core · at IdentityServerOptions.InputLengths · configuration key IdentityServer:InputLengths

How long each protocol parameter this server reads may be.

Mostly an abuse control: every value here arrives from a caller, several of them unauthenticated, and each is then split, compared, hashed, stored or logged. A bound is the cheapest thing that stops any of those being asked to do unbounded work.

InputLengthRestrictions.CodeVerifierMinLength is the exception, and it is not about abuse at all. RFC 7636 §4.1 requires a code_verifier of 43 to 128 characters because PKCE's whole protection is that an attacker holding an intercepted authorization code cannot produce the verifier. That attacker also holds the code_challenge — it travelled in the authorization request — so a short verifier is brute-forced offline and the code redeemed. The floor is what makes the search infeasible.

Every property here is enforced. A limit that nothing reads would be a setting an operator could tune while the request it names went on unbounded, which is the shape §1 of the parity matrix exists to remove — so parameters this server does not yet bound are absent rather than present and ignored.

Property Configuration key Type Default Description
IdentityServerOptions.InputLengths.ClientId IdentityServer:InputLengths:ClientId int 100 Maximum length of client_id. Defaults to 100.
IdentityServerOptions.InputLengths.Scope IdentityServer:InputLengths:Scope int 300 Maximum length of scope, the whole space-delimited list. Defaults to 300.
IdentityServerOptions.InputLengths.RedirectUri IdentityServer:InputLengths:RedirectUri int 400 Maximum length of redirect_uri. Defaults to 400.
IdentityServerOptions.InputLengths.Nonce IdentityServer:InputLengths:Nonce int 300 Maximum length of nonce. Defaults to 300.
IdentityServerOptions.InputLengths.State IdentityServer:InputLengths:State int 2000 Maximum length of state. Defaults to 2000.

The most generous bound here, because state is the one parameter clients legitimately pack: it is theirs, opaque to this server, and often carries an encoded return context. It is also the only one echoed back, which is why exceeding it is answered without a redirect — see the authorize validator.
IdentityServerOptions.InputLengths.LoginHint IdentityServer:InputLengths:LoginHint int 100 Maximum length of login_hint. Defaults to 100.
IdentityServerOptions.InputLengths.AcrValues IdentityServer:InputLengths:AcrValues int 300 Maximum length of acr_values. Defaults to 300.
IdentityServerOptions.InputLengths.CodeChallengeMinLength IdentityServer:InputLengths:CodeChallengeMinLength int 43 Minimum length of code_challenge (RFC 7636 §4.2). Defaults to 43.
IdentityServerOptions.InputLengths.CodeChallengeMaxLength IdentityServer:InputLengths:CodeChallengeMaxLength int 128 Maximum length of code_challenge. Defaults to 128.
IdentityServerOptions.InputLengths.CodeVerifierMinLength IdentityServer:InputLengths:CodeVerifierMinLength int 43 Minimum length of code_verifier (RFC 7636 §4.1). Defaults to 43.

Lowering this weakens PKCE for every client, and lowering it far enough removes PKCE's protection entirely while leaving every part of the exchange looking correct. It is settable because the specification names a number and a host may have to meet an older client, not because it is a knob.
IdentityServerOptions.InputLengths.CodeVerifierMaxLength IdentityServer:InputLengths:CodeVerifierMaxLength int 128 Maximum length of code_verifier. Defaults to 128.
IdentityServerOptions.InputLengths.BindingMessage IdentityServer:InputLengths:BindingMessage int 64 Maximum length of a CIBA binding_message. Defaults to 64.

Bounded by human patience rather than by storage: it exists to be read out and compared by a person on two devices, and a message nobody finishes comparing is a ceremony everyone learns to click through.
IdentityServerOptions.InputLengths.ClientNotificationToken IdentityServer:InputLengths:ClientNotificationToken int 1024 The longest client_notification_token accepted. Defaults to 1024.

Client-supplied and stored, so it is bounded like every other string a client sends. CIBA Core §7.1 asks for at least 128 bits of entropy and sets no ceiling, so the ceiling here is only about not storing an arbitrary amount of someone else's data: anything a client can reasonably mint fits far inside it.
IdentityServerOptions.InputLengths.IdTokenHint IdentityServer:InputLengths:IdTokenHint int 4000 The longest id_token_hint accepted. Defaults to 4000.

Checked before the token is parsed, so a client cannot make this server verify a signature over an arbitrary amount of input. Generous because an identity token carries whatever profile claims a client is entitled to, and one this server signed should never be refused for being this server's own size.
IdentityServerOptions.InputLengths.UserCode IdentityServer:InputLengths:UserCode int 100 The longest CIBA user_code accepted. Defaults to 100.

CIBA's only — the device flow's user code is a different thing under the same name, one this server generates rather than one a client sends. A user code is a PIN or a password, so the bound is about not handing a host's validator an arbitrary amount of input to compare, not about what a real one looks like.
IdentityServerOptions.InputLengths.LoginHintToken IdentityServer:InputLengths:LoginHintToken int 4000 The longest CIBA login_hint_token accepted. Defaults to 4000.

Duende's default, measured from its 8.0.1 package: a longer one is invalid_request.
IdentityServerOptions.InputLengths.DeviceCode IdentityServer:InputLengths:DeviceCode int 100 The longest device_code accepted at the token endpoint. Defaults to 100.

Duende's default, measured from its 8.0.1 package: a longer one is invalid_grant, before the store is asked.
IdentityServerOptions.InputLengths.ResourceIndicator IdentityServer:InputLengths:ResourceIndicator int 512 The longest resource indicator accepted (RFC 8707). Defaults to 512.

Duende's default, measured from its 8.0.1 package; an API's URI has no reason to come near it.
IdentityServerOptions.InputLengths.DPoPProofToken IdentityServer:InputLengths:DPoPProofToken int 4000 The longest DPoP proof accepted, at the token and pushed authorization endpoints. Defaults to 4000.

Duende's default, measured from its 8.0.1 package. Checked before the proof is parsed, so a client cannot make this server verify a signature over an arbitrary amount of input; a proof is a header, a key and a few claims.
IdentityServerOptions.InputLengths.ClientSecret IdentityServer:InputLengths:ClientSecret int 100 The longest client secret read from the Authorization header or the form. Defaults to 100.

A longer one is not a credential: the parser reads nothing, as Duende's does, and the request is answered as one with no client authentication. The Authorization header as a whole may be no longer than the base64 of a client id and secret at their limits.
IdentityServerOptions.InputLengths.UiLocale IdentityServer:InputLengths:UiLocale int 100 The longest ui_locales accepted at the authorize endpoint. Defaults to 100.
IdentityServerOptions.InputLengths.GrantType IdentityServer:InputLengths:GrantType int 100 The longest grant_type accepted at the token endpoint. Defaults to 100; a longer one is unsupported_grant_type.
IdentityServerOptions.InputLengths.AuthorizationCode IdentityServer:InputLengths:AuthorizationCode int 100 The longest authorization code accepted at the token endpoint. Defaults to 100; a longer one is invalid_grant, before the store is asked.
IdentityServerOptions.InputLengths.RefreshToken IdentityServer:InputLengths:RefreshToken int 100 The longest refresh_token accepted at the token endpoint. Defaults to 100; a longer one is invalid_grant, before the store is asked.
IdentityServerOptions.InputLengths.TokenHandle IdentityServer:InputLengths:TokenHandle int 100 The longest reference-token handle accepted wherever an access token is validated. Defaults to 100.

A JWT is held to InputLengthRestrictions.Jwt instead. Either too long is invalid_token before anything is looked up or verified.
IdentityServerOptions.InputLengths.AuthenticationRequestId IdentityServer:InputLengths:AuthenticationRequestId int 100 The longest CIBA auth_req_id accepted at the token endpoint. Defaults to 100; a longer one is invalid_grant.
IdentityServerOptions.InputLengths.DPoPKeyThumbprint IdentityServer:InputLengths:DPoPKeyThumbprint int 100 The longest dpop_jkt accepted at the authorize endpoint. Defaults to 100.

A SHA-256 JWK thumbprint is 43 characters.
IdentityServerOptions.InputLengths.Jwt IdentityServer:InputLengths:Jwt int 51200 The longest request object accepted, by value or fetched, and the longest signed CIBA request. Defaults to 51200.

Duende's default, measured from its 8.0.1 package, where it bounds the handler that reads the object.

CspOptions

Fdyay.IdentityServer.Configuration.CspOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.Csp · configuration key IdentityServer:Csp

Content-Security-Policy settings for this server's own pages.

Property Configuration key Type Default Description
IdentityServerOptions.Csp.Level IdentityServer:Csp:Level CspLevel Two The CSP version to write policies for. Defaults to CspLevel.Two.

It decides two real things rather than a syntax flavour. frame-ancestors is Level 2, so at Level 1 the framing refusal rests entirely on X-Frame-Options — which is why lowering this without CspOptions.AddDeprecatedHeaders leaves the approval screens framable. Hash sources are Level 2 too, so the check-session iframe falls back to 'unsafe-inline' for its own script.
IdentityServerOptions.Csp.AddDeprecatedHeaders IdentityServer:Csp:AddDeprecatedHeaders bool true Whether to also send the headers browsers used before CSP Level 2. Defaults to true.

X-Frame-Options: DENY and X-Content-Security-Policy. Both are superseded and both are still the only thing an old browser reads, and the page they protect is one where a single click grants an application access to a user's data. Turning them off is for a deployment that knows what its users run.

ValidationOptions

Fdyay.IdentityServer.Configuration.ValidationOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.Validation · configuration key IdentityServer:Validation

Checks applied to configured values, over and above whether they are configured.

Registration answers whether this server will send a browser somewhere. It does not answer whether the somewhere is a location at all, and the two are not the same question: a client-registration API, an administration screen or a SAML metadata document can put a URI into a store whose scheme runs script rather than navigating. This group is where that second question lives.

Property Configuration key Type Default Description
IdentityServerOptions.Validation.InvalidRedirectUriPrefixes IdentityServer:Validation:InvalidRedirectUriPrefixes ICollection<string> [ "javascript:", "data:", "vbscript:", "file:", "blob:", "about:", "view-source:" ] URI prefixes this server refuses to send a browser to, however the URI was registered. Matched case-insensitively against a normalised form of the URI.

A deny list rather than a list of permitted schemes, and the reason is native clients: a mobile application registers com.example.app:/callback and has every right to, so an allow list of http and https would refuse a legitimate registration in order to catch a hostile one. What the defaults have in common is that a browser asked to navigate to them either executes something (javascript:) or supplies its own document, and its own origin, rather than fetching one.

The list is settable, so a deployment that has a use for one of these can drop it, and one that knows its clients are all web applications can add to it.

PersistentGrantOptions

Fdyay.IdentityServer.Configuration.PersistentGrantOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.PersistentGrants · configuration key IdentityServer:PersistentGrants

What this server does with the grants it persists.

Property Configuration key Type Default Description
IdentityServerOptions.PersistentGrants.DataProtectData IdentityServer:PersistentGrants:DataProtectData bool true Whether a persisted grant's Data is protected with the host's data protection ring before it is stored. On by default.

What is in that column is why the default is on. A grant's Data is the serialized thing itself: for a refresh token or an authorization code, the whole claim set the subject was issued — every claim a profile service added included. Until 0.64.0 four stores wrote it as plaintext JSON, so the grant table held, in the clear, the full identity of everybody with a live session. The signing keys in that same database have been protected since key management shipped.

Turning it off does not make old rows unreadable, and neither does turning it on. This option governs writes only. A read always tries to unprotect and falls back to treating the value as plaintext, so a store holding both shapes at once — the ordinary state during an upgrade — reads correctly either way.

Off is a real choice, not a legacy setting. A host that keeps its grant store encrypted at rest by other means, or one that needs to read the column with a query rather than through this server, is not getting less protection by turning this off — it is getting the protection somewhere else. What it must not do is assume the column is unreadable while this is off.
IdentityServerOptions.PersistentGrants.DeleteOneTimeOnlyRefreshTokensOnUse IdentityServer:PersistentGrants:DeleteOneTimeOnlyRefreshTokensOnUse bool false Whether a OneTimeOnly refresh token is deleted when it is used, rather than kept as consumed. Off by default. Duende's, whose default is on.

On gives up replay detection. A consumed token presented again is the one sign that a handle was copied, and this server revokes the lineage when it sees one (RFC 9700 §4.14.2); a deleted token presented again is only unknown, refused without revoking anything, so the copy's successor lives on. Hence off here, where Duende's is on. On is for a host whose grant store must not keep used tokens until they expire.
IdentityServerOptions.PersistentGrants.ConsumedRefreshTokenGracePeriod IdentityServer:PersistentGrants:ConsumedRefreshTokenGracePeriod TimeSpan 00:00:00 How long after a OneTimeOnly refresh token is consumed it is still accepted if presented again. Zero — no grace, as in Duende's — by default. Ours: Duende's has no option, only the AcceptConsumedTokenAsync hook this sets.

It widens the replay window by exactly this much. A consumed token presented within it is redeemed again — a fresh access token and a fresh refresh token, forking the lineage — and is not seen as a replay, so a copied handle used within it goes unnoticed. Measured from the first consumption, so presenting the token again does not extend it; after it a consumed token is a replay as before, refused, and its whole lineage revoked, forks included. Everything else is checked as for an unconsumed token. It is for a client that races itself — two instances of a BFF refreshing with one token, or a request carrying the old one just after a refresh landed — and is kept as short as that race. Has no effect with PersistentGrantOptions.DeleteOneTimeOnlyRefreshTokensOnUse, which leaves nothing to accept. Negative is a configuration error: UseIdentityServer refuses it.

AuthenticationOptions

Fdyay.IdentityServer.Configuration.AuthenticationOptions in Fdyay.IdentityServer.Core · at IdentityServerOptions.Authentication · configuration key IdentityServer:Authentication

The session cookie's policy, and the cookies this server writes itself.

The session cookie's lifetime, sliding expiration and SameSite mode are Duende's options here since 0.101.0, at Duende's defaults, read where Duende reads them: when the session cookie's CookieAuthenticationOptions are configured, and — sliding — when a client's token slides a server-side session. Until then they were declined as a second source of truth for values ASP.NET Core owns; parity took them. What made the refusal reasonable still holds: they are applied as configuration, so a host that sets the scheme's own options after AddIdentityServer() still wins, and a test still says so.

The check-session cookie is the other case. SessionStateService writes it with Response.Cookies.Append, so no options system reaches it at all, and its name was a constant read at four sites — one of them inside the JavaScript the check-session iframe runs. Two identity servers on one registrable domain wrote the same cookie and each saw the other's browser state.

Its SameSite mode is deliberately not here, and the reason is a limitation worth stating rather than a knob worth adding. The cookie is written SameSite=None with Secure, because the iframe runs in the relying party's page and reads it from a third-party context. Over plain HTTP the browser drops it whatever SameSite says — so an option here would not make check-session work in an HTTP development setup; it would take relaxing Secure as well, on a cookie, which is not a setting this server is going to offer. Check-session does not work over plain HTTP, and that is the honest sentence. A single option would have read like a fix for it.

Property Configuration key Type Default Description
IdentityServerOptions.Authentication.CheckSessionCookieName IdentityServer:Authentication:CheckSessionCookieName string "idsrv.session" The name of the cookie the check-session iframe reads. Defaults to idsrv.session.

Read by the service that writes the cookie and substituted into the script that reads it. Those are the two halves, and honouring one without the other would leave an iframe polling a cookie name nothing writes — a session that never appears to change, which a relying party cannot tell apart from a session that is simply still valid.
IdentityServerOptions.Authentication.CheckSessionCookieDomain IdentityServer:Authentication:CheckSessionCookieDomain string? null The domain to scope the check-session cookie to, or null to leave it host-only.

Null rather than a computed value: host-only is the narrower default, and a host that needs the iframe reachable from a sibling subdomain is making a deliberate widening it should have to write down.
IdentityServerOptions.Authentication.CoordinateClientLifetimesWithUserSession IdentityServer:Authentication:CoordinateClientLifetimesWithUserSession bool false Whether every client's tokens live only as long as the user's session here, unless the client says otherwise with Client.CoordinateLifetimeWithUserSession. Defaults to false, as in Duende.
IdentityServerOptions.Authentication.CookieLifetime IdentityServer:Authentication:CookieLifetime TimeSpan 10:00:00 How long the session cookie lasts. Defaults to 10 hours, as in Duende.
IdentityServerOptions.Authentication.CookieSlidingExpiration IdentityServer:Authentication:CookieSlidingExpiration bool false Whether the session cookie's expiry moves with use. Defaults to false, as in Duende: a session ends AuthenticationOptions.CookieLifetime after sign-in however active it was.

Also what lets a coordinating client's token renew the cookie's own ticket when it slides a server-side session; without it only the session's row slides.
IdentityServerOptions.Authentication.CookieSameSiteMode IdentityServer:Authentication:CookieSameSiteMode SameSiteMode None The SameSite mode of the session cookie and the external sign-in cookie. Defaults to SameSiteMode.None, as in Duende, which sends them on cross-site requests and so needs HTTPS.
IdentityServerOptions.Authentication.RequireCspFrameSrcForSignout IdentityServer:Authentication:RequireCspFrameSrcForSignout bool true Whether the signed-out page, which loads each client's front-channel logout URL in an iframe, carries a Content-Security-Policy whose frame-src names those clients' origins. On by default, as in Duende.

Duende 8.0.1's, measured: when off, that page carries no policy at all. When on — and until 0.106.0 there was no choice — the page has this library's interactive-page policy; until 0.106.0 that policy had no frame-src, so default-src 'none' blocked every one of the page's iframes in a browser.
IdentityServerOptions.Authentication.RequireAuthenticatedUserForSignOutMessage IdentityServer:Authentication:RequireAuthenticatedUserForSignOutMessage bool false Whether an end-session request from a user with no session here has its parameters ignored — id_token_hint, post_logout_redirect_uri and state. Off by default, as in Duende.
IdentityServerOptions.Authentication.CookieAuthenticationScheme IdentityServer:Authentication:CookieAuthenticationScheme string? null The cookie scheme that holds a user's session here. When not set, the host's default authenticate scheme — and when there is none, IdentityServerConstants.DefaultCookieAuthenticationScheme if it is registered.

Duende 8.0.1's, measured: what a host sets when its default authentication scheme is a policy scheme, or its own cookie, so this server reads, writes and ends the session where the host's sign-in put it. A scheme named here that is not registered is refused at startup. Since 0.107.0; until then idsrv was hard-coded at about fifteen sites, a few of which consulted the default scheme first and the rest did not.

DynamicProviderOptions

Fdyay.IdentityServer.Configuration.DynamicProviderOptions in Fdyay.IdentityServer.AspNetCore · configured with AddDynamicProviders · configuration key DynamicProvider

How dynamic providers are served, and which kinds this host has registered.

Property Configuration key Type Default Description
DynamicProviderOptions.PathPrefix DynamicProvider:PathPrefix PathString "/federation" Where a dynamic provider's callbacks live. Defaults to /federation.

A dynamic scheme cannot share a callback path with any other, so each gets one under this prefix — /federation/{scheme}/signin. Static registrations set their own and are untouched.
DynamicProviderOptions.PathMatchingCallback code only Func<HttpContext, Task<string?>>? null Names the dynamic scheme a request is a callback for, or null when it is for none. When set, it is asked instead of DynamicProviderOptions.PathPrefix. Duende 8.0.1's, measured.

For a host whose dynamic providers call back somewhere other than {PathPrefix}/{scheme}/… — a path per tenant, say. The callback paths a handler answers are its own options; this only says which scheme's handler a request is handed to.
DynamicProviderOptions.SignInScheme DynamicProvider:SignInScheme string "idsrv.external" The scheme a dynamic provider signs the user in to: the external cookie. Duende's default.
DynamicProviderOptions.SignOutScheme DynamicProvider:SignOutScheme string? "idsrv" The scheme a dynamic provider signs out of when its upstream says the session ended: this server's session cookie, which is also what it reads as when unset. Duende's default.

LocalApiAuthenticationOptions

Fdyay.IdentityServer.Hosting.LocalApiAuthenticationOptions in Fdyay.IdentityServer.AspNetCore · configured with AddLocalApi, AddLocalApiAuthentication · configuration key LocalApiAuthentication

What the local API handler gives a host a say over.

Deliberately small. A local API is an API this server hosts itself, so almost everything a general-purpose JWT handler makes configurable — the authority, the signing keys, the issuer, the clock skew — is already settled by the server the handler is running inside, and offering it twice invites the two to disagree.

It derives from AuthenticationSchemeOptions (Microsoft.AspNetCore.Authentication), whose settings are that framework's and are not listed here.

Property Configuration key Type Default Description
LocalApiAuthenticationOptions.ExpectedScope LocalApiAuthentication:ExpectedScope string "IdentityServerApi" The scope a token has to carry. Defaults to IdentityServerApi.

Required, and there is no way to say "any token this server issued". That would be a door opened by every token in the deployment — including one minted for an unrelated API, by a client the host never meant to let near its administration surface. A host that genuinely wants it can write four lines of its own handler; it will not get it here by leaving a property empty.
LocalApiAuthenticationOptions.SaveToken LocalApiAuthentication:SaveToken bool true Whether the token is kept so the API can read it back. Defaults to true.

On by default because a local API calling on to something else is the ordinary case, and a token it cannot reach is a token it will be handed a second way instead.

Read it back by naming this scheme: HttpContext.GetTokenAsync(IdentityServerConstants.LocalApi.AuthenticationScheme, "access_token"). The overload without a scheme reads the default authenticate scheme, which in any host that also serves this server's own pages is a browser cookie holding no access token — so it answers null, and it answers null in exactly the deployment this option exists for.
LocalApiAuthenticationOptions.TokenMode LocalApiAuthentication:TokenMode LocalApiTokenMode DPoPAndBearer Which schemes a token is taken under. Defaults to LocalApiTokenMode.DPoPAndBearer.

Duende's defaults to LocalApiTokenMode.BearerOnly. This handler has taken a token under either scheme since 0.45.0, so its default stays both: a default of Bearer only would turn away every caller holding a token bound to its key. Whatever the mode, a token bound to a key is refused under Bearer — the mode decides which schemes are read, never whether a binding is held to.
LocalApiAuthenticationOptions.Events LocalApiAuthentication:Events LocalApiAuthenticationEvents see LocalApiAuthenticationEvents The host's hook for shaping the principal the API sees.

LocalApiAuthenticationEvents

Fdyay.IdentityServer.Hosting.LocalApiAuthenticationEvents in Fdyay.IdentityServer.AspNetCore · at LocalApiAuthenticationOptions.Events · configuration key LocalApiAuthentication:Events

Host hooks on the local API handler.

Property Configuration key Type Default Description
LocalApiAuthenticationOptions.Events.OnClaimsTransformation code only Func<LocalApiClaimsTransformationContext, Task> a default handler Runs after a token is accepted and before the API is reached.

A shaping hook, not a second gate: by the time it runs the token has been validated, its binding checked and its scope required, and replacing the principal here cannot undo any of that. A host that wants to refuse a caller refuses it in authorization, where a refusal is visible as one.

SamlAuthenticationOptions

Fdyay.IdentityServer.Saml.Sp.SamlAuthenticationOptions in Fdyay.IdentityServer.Saml · configured with services.Configure<SamlAuthenticationOptions>(…) · configuration key SamlAuthentication

A stored SAML provider's settings a host can override, per scheme, in code.

Duende 8.0.1's SamlAuthenticationOptions, measured: named options for each saml scheme, filled from the stored row and DynamicProviderOptions first, so a host's services.Configure<SamlAuthenticationOptions>(scheme, …) or PostConfigure sees those values and replaces the ones it names. What it settles wins over the row; what it leaves null falls back to the row.

An AuthenticationSchemeOptions because Duende's is, and because that is what lets the same mechanism that fills a handler's options from a row fill these.

It derives from AuthenticationSchemeOptions (Microsoft.AspNetCore.Authentication), whose settings are that framework's and are not listed here.

Property Configuration key Type Default Description
SamlAuthenticationOptions.SpEntityId SamlAuthentication:SpEntityId string? null The entity id this server presents. Null falls back to the row's, then to this server's issuer.
SamlAuthenticationOptions.OutboundSigningAlgorithm SamlAuthentication:OutboundSigningAlgorithm string? null The signature method this server signs its messages to the provider with.
SamlAuthenticationOptions.WantAssertionsSigned SamlAuthentication:WantAssertionsSigned bool? null Whether this server asks for signed assertions.

Carried for Duende's shape, and not able to turn the requirement off: this server's service provider refuses an unsigned assertion whatever this says, and its metadata says WantAssertionsSigned="true" because that is what it does. A scheme configured to ask for less is logged as a warning when its options are built.
SamlAuthenticationOptions.SignInScheme SamlAuthentication:SignInScheme string? null The cookie a signed-in user lands in. Null falls back to DynamicProviderOptions.SignInScheme.
SamlAuthenticationOptions.SignOutScheme SamlAuthentication:SignOutScheme string? null The session an inbound LogoutRequest ends. Null falls back to DynamicProviderOptions.SignOutScheme.

SamlOptions

Fdyay.IdentityServer.Saml.Configuration.SamlOptions in Fdyay.IdentityServer.Saml · configured with AddSaml · configuration key Saml

Options for the native SAML implementation.

Property Configuration key Type Default Description
SamlOptions.EntityId Saml:EntityId string? null The IdP entity ID advertised in metadata and assertions. Defaults to the issuer when null.
SamlOptions.SigningCertificate code only X509Certificate2? null A certificate to sign with instead of this server's key material. Null (the default) signs with the server's current signing key, as Duende's does.

Read by the default ISamlSigningService: when set, it signs every assertion, response and logout message and is the one key metadata publishes, and key rotation does not reach SAML. Null, the signing key is the one IKeyMaterialService signs tokens with — an RSA key wrapped in a certificate of its own — so it rotates with them. Duende has no such option; it is kept for a host whose partners pinned a certificate. Until 0.144.0 it was required.
SamlOptions.Metadata Saml:Metadata SamlMetadataOptions see SamlMetadataOptions The cacheDuration and validUntil published metadata carries. Duende's Metadata.
SamlOptions.ClockSkew Saml:ClockSkew TimeSpan 00:05:00 Tolerance applied when checking assertion time conditions. Defaults to 5 minutes.
SamlOptions.EnableIdpInitiatedSignOn Saml:EnableIdpInitiatedSignOn bool false Whether this server will start a sign-on no service provider asked for. Defaults to false.

The IdP-initiated half of the Web SSO profile (§4.1.5): a link in this server's own portal that posts an assertion to a registered service provider. It is a capability rather than a default because the request that starts it carries no message this server can authenticate — that is what "unsolicited" means — so the decision to expose a route that signs a user into a service provider on a GET belongs to the host.

Read by saml/sso/initiate since 0.59.0, which answers nothing until it is set. Documented until 0.178.0 as inert, a note from the commit that declared it which outlived the commit that read it.
SamlOptions.AssertionLifetime Saml:AssertionLifetime TimeSpan 00:05:00 How long an issued assertion remains valid. Defaults to 5 minutes.
SamlOptions.DefaultSigningBehavior Saml:DefaultSigningBehavior SamlSigningBehavior SignAssertion What is signed in a response to a provider that does not say; defaults to the assertion, as Duende's does.
SamlOptions.RequireHttpsServiceProviderUrls Saml:RequireHttpsServiceProviderUrls bool true Whether a registered service provider's reply and logout addresses must be https. Defaults to true.

A SAML response carries a signed assertion, which is a bearer credential for whoever holds it, and the registration is the only thing that decides where it is delivered. Plaintext to a host that is not loopback puts that credential on a wire, so as of 0.71.0 such a registration is refused where it is read rather than served.

Loopback is exempt whatever this says, because a partner on the developer's own machine is the case https cannot be asked of, and a credential that never leaves the host is not on a wire. Setting this to false is the escape for a deployment terminating TLS somewhere this server cannot see — it is a statement that the plaintext hop is inside a boundary, not that the hop does not exist.
SamlOptions.WantAuthnRequestsSigned Saml:WantAuthnRequestsSigned bool true Whether an AuthnRequest must be signed. Defaults to true, as Duende's does.

Duende 8.0.1's SamlOptions.WantAuthnRequestsSigned, measured: advertised in metadata as the IdP descriptor's WantAuthnRequestsSigned, and enforced for every service provider that does not say otherwise with SamlServiceProvider.RequireSignedAuthnRequests. A provider with no SamlServiceProvider.RequestSigningCertificate cannot sign, so it is refused unless it opts out.
SamlOptions.RequireSignedLogoutResponses Saml:RequireSignedLogoutResponses bool true Whether a LogoutResponse must be signed. Defaults to true, as Duende's does.

Duende 8.0.1's SamlOptions.RequireSignedLogoutResponses, measured: read at the single logout endpoint for a LogoutResponse only, for every service provider that does not say otherwise with SamlServiceProvider.RequireSignedLogoutResponses. False lets an unsigned answer through; one that carries a signature is still held to it. Until 0.154.0 every LogoutResponse had to be signed, as it still must by default.
SamlOptions.MatchLogoutRequestToSession Saml:MatchLogoutRequestToSession bool false Whether a verified LogoutRequest must name a SAML session this browser holds with the provider before it ends the session. Defaults to false: such a request ends the session, as it always has.

True runs Duende 8.0.1's LogoutRequestValidator.ValidateSessionAsync checks, measured, for every service provider that does not say otherwise with SamlServiceProvider.MatchLogoutRequestToSession. For a signed-in user, a request with no NameID, or whose NameID matches none of the provider's sessions here, is refused; one from a provider with no session here, or whose SessionIndex names none, is answered Success and ends nothing. Duende always runs them; Ours: off by default (decided 2026-10-14), because each changes what this server does with a verified request. New in 0.159.0.
SamlOptions.DefaultRequestMaxAge Saml:DefaultRequestMaxAge TimeSpan 00:05:00 How old an AuthnRequest's IssueInstant may be. Defaults to 5 minutes, as Duende's does.

Since 0.178.0 also how old a LogoutRequest may be when it reaches this server's service provider (SamlSpHandler), with SamlSpOptions.ClockSkew added there.
SamlOptions.MaxMessageSize Saml:MaxMessageSize int 1048576 The longest inbound SAML message, in characters once decoded. Defaults to 1 MiB, as Duende's does.

Checked before a POST-bound message is decoded and while a redirect-bound one is inflated, so a few kilobytes of deflated input cannot be made to expand without end, and again when the XML is loaded.

Since 0.178.0 at this server's service provider too — the SAMLResponse its assertion consumer reads and the LogoutRequest its single logout endpoint reads, and in SamlResponseValidator — where until then neither was bounded. Duende 8.0.1's service provider bounds neither, measured.
SamlOptions.MaxRelayStateLength Saml:MaxRelayStateLength int 80 The longest RelayState accepted, in UTF-8 bytes. Defaults to 80, the limit SAML Bindings §3.4.3 sets.
SamlOptions.SupportedNameIdFormats Saml:SupportedNameIdFormats ICollection<string> [ "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress", "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" ] The NameID formats a request may ask for, and metadata advertises, in this order. Defaults to emailAddress and unspecified, as Duende's does.

A request naming a format not listed here — or, naming none, from a provider whose SamlServiceProvider.DefaultNameIdFormat is not listed — is refused with InvalidNameIDPolicy. The default ISamlNameIdGenerator issues emailAddress from SamlOptions.EmailNameIdClaimType and every other format from sub, so listing persistent or transient labels the subject id with that format, as Duende's does; a different value is a generator of the host's own.
SamlOptions.EmailNameIdClaimType Saml:EmailNameIdClaimType string "email" The claim an emailAddress NameID is read from. Defaults to email, as Duende's does.
SamlOptions.DefaultAuthnContextMappings Saml:DefaultAuthnContextMappings IReadOnlyDictionary<string, string> { "pwd": "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport", "external": "urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified" } The acr and amr values and the AuthnContextClassRef each is issued as, for a provider with no mappings of its own. Defaults to Duende's two: pwd as PasswordProtectedTransport, external as unspecified.

The signed-in user's acr is looked up first, then each amr in the order the claims are held; the first found is issued, and unspecified when none is. Until 0.134.0 every assertion said PasswordProtectedTransport, however the user had signed in.
SamlOptions.DefaultClaimMappings Saml:DefaultClaimMappings IReadOnlyDictionary<string, string> { "name": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "email": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", "role": "http://schemas.xmlsoap.org/ws/2005/05/identity/role" } The claim types and the attribute name each is issued as, for a provider with no mappings of its own. Defaults to Duende's three: name, email and role as the WS-Federation claim URIs.

A claim type not listed is issued under its own name. role maps to http://schemas.xmlsoap.org/ws/2005/05/identity/role — without the claims/ segment the other two have — because that is the value Duende 8.0.1 ships. Until 0.141.0 the attributes were the session's name and email claims under those names.
SamlOptions.Endpoints Saml:Endpoints SamlEndpointOptions see SamlEndpointOptions Where the SAML endpoints are served, and over which bindings. Duende's SamlOptions.Endpoints.
SamlOptions.SigninStateLifetime Saml:SigninStateLifetime TimeSpan 00:15:00 How long a sign-on waits for its user at the login page before the request it arrived with is dropped. Defaults to 15 minutes, as Duende's SigninStateLifetime does.

Written onto each SamlSignInState as its ExpiresAt when it is stored, so a store of the host's own can expire it without knowing these options, as Duende writes its ExpiresAtUtc. Until 0.145.0 the in-memory store kept every state for twenty minutes, and a store of the host's own was told nothing.
SamlOptions.LogoutSessionLifetime Saml:LogoutSessionLifetime TimeSpan 00:05:00 How long a single logout sequence may take before it is dropped. Defaults to 5 minutes, as Duende's LogoutSessionLifetime does.

Written onto each SamlLogoutSession as its ExpiresAt, for the same reason. Until 0.145.0 the in-memory store kept every sequence for a fixed five minutes.
SamlOptions.AuthnRequestErrorInspector code only Action<ReadErrorInspectorContext<SamlAuthnRequest>>? null Called when an inbound AuthnRequest does not read cleanly, with every error found; null (the default) refuses it as before. Duende's AuthnRequestErrorInspector.

The inspector may remove an error, or set its Error.Ignore, and the request is then read and validated as any other; it may also set a corrected request as ReadErrorInspectorContext.Data — a date in a partner's quirky format, say. Called only when there is an error, and at each read of the request (the sign-on, its resumption, the login page's context). Data.Issuer is unverified when it is called, as Duende warns: no decision should rest on it alone.

It cannot make a message trusted. The signature is checked after the inspector returns, over the message as received and against the provider the request finally names, and every check the validator makes is still made. In Duende's the signature is verified while reading, before the inspector runs, against the issuer as sent, and the request's TrustLevel is a settable property of the data the inspector is handed.
SamlOptions.LogoutRequestErrorInspector code only Action<ReadErrorInspectorContext<SamlLogoutRequest>>? null Called when an inbound LogoutRequest does not read cleanly; null (the default) refuses it as before. Duende's LogoutRequestErrorInspector, as SamlOptions.AuthnRequestErrorInspector is for an AuthnRequest.
SamlOptions.LogoutResponseErrorInspector code only Action<ReadErrorInspectorContext<SamlLogoutResponse>>? null Called when an inbound LogoutResponse does not read cleanly; null (the default) refuses it as before. Duende's LogoutResponseErrorInspector, as SamlOptions.AuthnRequestErrorInspector is for an AuthnRequest.

SamlMetadataOptions

Fdyay.IdentityServer.Saml.Configuration.SamlMetadataOptions in Fdyay.IdentityServer.Saml · at SamlOptions.Metadata · configuration key Saml:Metadata

How long a partner may keep this identity provider's metadata. Duende's SamlMetadataOptions.

Written on the published EntityDescriptor as cacheDuration and validUntil (SAML Metadata §2.3.1): how often a partner should fetch it again, and the moment it stops being usable at all. The signing key published there rotates with this server's key material, so a partner that refreshes within SamlMetadataOptions.CacheDuration learns a new key before it signs. As of 0.144.0; until then the metadata said neither.

Property Configuration key Type Default Description
SamlOptions.Metadata.CacheDuration Saml:Metadata:CacheDuration TimeSpan 12:00:00 How long a partner may cache the metadata before fetching it again. Defaults to 12 hours, as Duende's does.
SamlOptions.Metadata.ExpiryDuration Saml:Metadata:ExpiryDuration TimeSpan 5.00:00:00 How long after it is served the metadata expires. Defaults to 5 days, as Duende's does.

SamlEndpointOptions

Fdyay.IdentityServer.Saml.Configuration.SamlEndpointOptions in Fdyay.IdentityServer.Saml · at SamlOptions.Endpoints · configuration key Saml:Endpoints

Where the SAML endpoints are served, and over which bindings. Duende 8.0.1's SamlEndpointOptions, measured.

Read per request, wherever a path is needed — the router, the return URL, the Destination an inbound message must name, and the metadata — so one setting moves all of them at once, whether it is made in AddSaml's callback or in a Configure<SamlOptions> after it. Duende reads its paths once, from AddSaml's callback, to register its routes.

The paths keep this server's defaults rather than Duende's /Saml2/SSO and /Saml2/SLO: they are published in metadata and configured at every partner, so moving them is the host's decision to make, not an upgrade's.

Property Configuration key Type Default Description
SamlOptions.Endpoints.SingleSignOnServicePath Saml:Endpoints:SingleSignOnServicePath string "/saml/sso" The single sign-on service's path. Defaults to /saml/sso.

The IdP-initiated door is served beneath it, at {path}/initiate.
SamlOptions.Endpoints.SingleSignOnServiceBindings Saml:Endpoints:SingleSignOnServiceBindings ICollection<string> [ "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ] The bindings the single sign-on service accepts and metadata advertises. Defaults to HTTP-Redirect and HTTP-POST, as Duende's does; empty switches the service off.
SamlOptions.Endpoints.SingleSignOnCallbackPath Saml:Endpoints:SingleSignOnCallbackPath string "/saml/sso/callback" Where the browser comes back from the login page to have its sign-on answered. Defaults to /saml/sso/callback.
SamlOptions.Endpoints.SingleLogoutServicePath Saml:Endpoints:SingleLogoutServicePath string "/saml/slo" The single logout service's path. Defaults to /saml/slo.
SamlOptions.Endpoints.SingleLogoutServiceBindings Saml:Endpoints:SingleLogoutServiceBindings ICollection<string> [ "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect", "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" ] The bindings the single logout service accepts and metadata advertises. Defaults to HTTP-Redirect and HTTP-POST, as Duende's does; empty switches the service off.
SamlOptions.Endpoints.StateIdParameterName Saml:Endpoints:StateIdParameterName string "samlStateId" The query parameter the return URL carries the stored sign-in's reference in. Defaults to samlStateId, as Duende's does.

SamlSpOptions

Fdyay.IdentityServer.Saml.Sp.SamlSpOptions in Fdyay.IdentityServer.Saml · configured with AddExternalSaml2, AddSaml2 · configuration key SamlSp

Options for acting as a SAML 2.0 service provider toward an upstream identity provider.

It derives from RemoteAuthenticationOptions (Microsoft.AspNetCore.Authentication), whose settings are that framework's and are not listed here.

Property Configuration key Type Default Description
SamlSpOptions.SpEntityId SamlSp:SpEntityId string null Our entity ID as an SP (used as the AuthnRequest issuer and expected assertion audience).
SamlSpOptions.IdpEntityId SamlSp:IdpEntityId string null The upstream IdP's entity ID (expected assertion issuer).
SamlSpOptions.IdpSingleSignOnUrl SamlSp:IdpSingleSignOnUrl string null The upstream IdP's Single Sign-On URL (HTTP-Redirect binding).
SamlSpOptions.IdpSingleLogoutUrl SamlSp:IdpSingleLogoutUrl string? null The upstream IdP's Single Logout URL (HTTP-Redirect binding). Required to initiate SP logout.
SamlSpOptions.IdpSingleSignOnBinding SamlSp:IdpSingleSignOnBinding string "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" How the AuthnRequest reaches the upstream IdP's Single Sign-On URL: HTTP-Redirect (the default) or HTTP-POST, as Bindings names them.

Duende 8.0.1's service provider binds its request either way (its SamlProvider.BindingType). A posted request is signed inside the XML rather than beside it, and arrives as a form the browser submits. Since 0.109.0.
SamlSpOptions.OutboundSigningAlgorithm SamlSp:OutboundSigningAlgorithm string? null The signature method this service provider signs with, as a URI. Null — the default — follows the key: RSA-SHA256, or ECDSA with the hash its curve pairs with.

Duende 8.0.1's OutboundSigningAlgorithm, read for every message it signs: the AuthnRequest, the LogoutRequest and the LogoutResponse. It has to be a method this server accepts — SHA-256, SHA-384 or SHA-512, RSA or ECDSA to match SamlSpOptions.SigningCertificate's key — so SHA-1, which Duende can still be told to use, is refused at startup here. Since 0.109.0.
SamlSpOptions.SignOutScheme SamlSp:SignOutScheme string? null The scheme whose session an inbound LogoutRequest ends. Defaults to the sign-in scheme.

The same shape OpenIdConnectOptions has, and for the same reason: the scheme an external identity is written to is not the scheme that holds the session. When the identity provider ends the session at its end and tells us, what has to go is the local session — and dropping that cookie is what makes the rest of the sign-out sequence run, since 0.43.0 wraps the handler that holds it. Left null it falls back to RemoteAuthenticationOptions.SignInScheme, which is the honest default for a handler registered outside an identity server: there is no other session it knows of.
SamlSpOptions.SignedOutCallbackPath SamlSp:SignedOutCallbackPath PathString "/signout-saml" The path the IdP posts the LogoutResponse back to. Defaults to /signout-saml.
SamlSpOptions.IdpSigningCertificate code only X509Certificate2 null The upstream IdP's signing certificate, used to verify assertions.
SamlSpOptions.MetadataPath SamlSp:MetadataPath PathString "/saml-metadata" Where this service provider publishes its metadata. Defaults to /saml-metadata.

Public information by definition — an entity id, a reply address, and the certificate a partner encrypts to. Set it to PathString.Empty to publish nothing, at the cost of handing the same values over by some other route.
SamlSpOptions.SigningCertificate code only X509Certificate2? null Our certificate for signing the messages we send. Null to send them unsigned.

Needs the private key. A partner identity provider that requires signed requests refuses an unsigned one, and until 0.70.0 there was no key here to sign with — so the three messages this handler sends all went out unsigned and the metadata said so.

All three, which is the part worth stating: the AuthnRequest that starts a sign-on, the LogoutRequest that starts a logout, and the LogoutResponse that answers the provider's. Signing the two requests and not the response would satisfy a partner's AuthnRequestsSigned and still fail it at the end of a logout, which is the harder failure to attribute.

Setting it changes what the published metadata claims, because the two cannot honestly disagree: the descriptor's AuthnRequestsSigned follows this, and the certificate is published as a signing KeyDescriptor. Claiming to sign without publishing the key leaves a partner told to expect a signature it has no way to verify.

The messages travel on the HTTP-Redirect binding, so the signature is the detached one on the query string (Bindings §3.4.4.1) rather than an enveloped XML signature — a DEFLATEd message in a URL has nowhere to carry one.
SamlSpOptions.DecryptionCertificate code only X509Certificate2? null Our certificate for decrypting an EncryptedAssertion. Null when we publish no encryption key.

Needs the private key: a partner IdP encrypts the content key to the public half.
SamlSpOptions.AllowIdpInitiatedSignOn SamlSp:AllowIdpInitiatedSignOn bool false Whether an assertion arriving for a request this server never made is accepted. Defaults to false.

Off, because the correlation this gives up is doing real work: a solicited response is tied to state this handler protected into RelayState when it sent the request, which is what says this browser started this sign-on. An unsolicited assertion has none of that, so accepting one is a decision about a partner IdP that a host makes deliberately.

Accepting them never means ignoring InResponseTo. An unsolicited response must name no request at all; one that names a request, arriving with no state, is a solicited response somebody captured.

The sign-in is recorded against this scheme — the scheme item the external sign-in page reads — so the provider's subject is looked up among this provider's users and no other's, whatever the assertion's attributes say. Each assertion is accepted once (SAML Profiles §4.1.4.5). Both since 0.178.0: until then an unsolicited sign-in recorded no scheme, and the page took the provider from the identity's own idp claim, which an attribute could supply. Read since 0.59.0; documented until 0.178.0 as inert, which it was not.
SamlSpOptions.IdpInitiatedReturnPath SamlSp:IdpInitiatedReturnPath PathString "/" Where the browser lands after an unsolicited sign-on. Defaults to /.

There is no return URL to honour: nothing on this site asked for the sign-on, so there is nowhere it was going. The IdP's RelayState is not that destination either — it is a value the partner chose, and navigating to it would make this a redirector for anyone who can reach the reply address.

The browser lands here with the identity in the external cookie; with the shipped pages it is the external sign-in callback (/Account/ExternalLogin?handler=Callback) that turns it into a session. Read since 0.59.0; documented until 0.178.0 as inert, which it was not.
SamlSpOptions.RequireEncryptedAssertion SamlSp:RequireEncryptedAssertion bool false Whether an assertion that arrives unencrypted is refused. Defaults to false.

Set it once the partner IdP is known to encrypt. Accepting either shape until then is the common case; accepting either shape afterwards lets whoever is on the path strip the encryption.
SamlSpOptions.NameIdClaimType SamlSp:NameIdClaimType string "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" An additional claim type the SAML NameID is mapped to. Defaults to ClaimTypes.NameIdentifier, which the external identity carries either way.

The NameID always arrives as ClaimTypes.NameIdentifier, because that is the type the shipped external-login page reads to find the provider subject and the type the sign-out path reads off the local principal to name the user back to the identity provider. Setting this adds a second claim of the given type for a deployment whose own external-login handling reads something else.

It used to replace the canonical type, which made every value but the default a registration that broke sign-in outright and sent a LogoutRequest naming nobody. Fixed in 0.52.0; a host that had set it and worked around the break needs no change, because the claim it asked for is still there.
SamlSpOptions.ClockSkew SamlSp:ClockSkew TimeSpan 00:05:00 Tolerance applied when checking assertion time conditions. Defaults to 5 minutes.

Since 0.178.0 also an inbound LogoutRequest's: its NotOnOrAfter, and an IssueInstant neither further ahead than this nor older than SamlOptions.DefaultRequestMaxAge and this together. An assertion's and a logout request's ID is remembered until its own expiry plus this, which is when it would be refused anyway.
SamlSpOptions.StateDataFormat code only ISecureDataFormat<AuthenticationProperties> null Protects the relay state that correlates a response to its request.

DapperStoreOptions

Fdyay.IdentityServer.Dapper.Configuration.DapperStoreOptions in Fdyay.IdentityServer.Dapper · configured with AddDapperStores · configuration key DapperStore

Options for the Dapper-backed stores.

Property Configuration key Type Default Description
DapperStoreOptions.Provider DapperStore:Provider DatabaseProvider Sqlite The database provider. Defaults to SQLite.
DapperStoreOptions.ConnectionString DapperStore:ConnectionString string "" The ADO.NET connection string.
DapperStoreOptions.InitializeSchema DapperStore:InitializeSchema bool true Whether the schema is created on startup. Defaults to true.

Set this to false where the schema is owned outside the application — a migration project or a DACPAC — so that the deployed schema stays the single source of truth and the application never writes DDL.
DapperStoreOptions.Stores DapperStore:Stores DapperStores All Which stores to back with the database. Defaults to DapperStores.All.
DapperStoreOptions.EnableTokenCleanup DapperStore:EnableTokenCleanup bool false Whether expired persisted grants are swept in the background. Defaults to false.

Off by default because a host whose schema is managed elsewhere may not want the application issuing deletes. Leaving it off means something else has to prune the table — nothing else does it.
DapperStoreOptions.TokenCleanupInterval DapperStore:TokenCleanupInterval TimeSpan 01:00:00 How often the sweep runs. Defaults to one hour.
DapperStoreOptions.RemoveConsumedTokens DapperStore:RemoveConsumedTokens bool false Whether consumed grants are removed as well as expired ones. Defaults to false.

A consumed grant cannot be redeemed again, so keeping it only preserves the record that it was used. Turn this on where that record is not wanted and the table would otherwise keep every spent one.

ClientCredentialsClient

Fdyay.AccessTokenManagement.ClientCredentialsClient in Fdyay.AccessTokenManagement · configured with AddClient · configuration key ClientCredentialsClient

A registered client-credentials client: where to ask for a token, and as whom.

Property Configuration key Type Default Description
ClientCredentialsClient.TokenEndpoint ClientCredentialsClient:TokenEndpoint Uri? null The authorization server's token endpoint.
ClientCredentialsClient.ClientId code only ClientId default The client_id sent with the token request.
ClientCredentialsClient.ClientSecret code only ClientSecret default The client_secret sent with the token request.
ClientCredentialsClient.Scope code only Scope? null The scope to request, or null to let the authorization server decide.
ClientCredentialsClient.HttpClientName ClientCredentialsClient:HttpClientName string? null The named HttpClient the token request itself travels on.

Not the client the token is later attached to — this one. It exists because the backchannel to the authorization server may need handling the application's outbound calls do not: a development certificate to trust, a proxy, a client certificate.
ClientCredentialsClient.ExpirationSkew ClientCredentialsClient:ExpirationSkew TimeSpan 00:01:00 How long before expiry a cached token stops being handed out. Defaults to one minute.

A token that expires in flight is rejected by the resource server, and the caller sees a 401 it did nothing to deserve. The window has to cover the request's own travel time, so it is a margin rather than a precision setting.
ClientCredentialsClient.TokenRequestTimeout ClientCredentialsClient:TokenRequestTimeout TimeSpan 00:00:10 How long the token request itself may take before it is given up on. Ten seconds.

The bound on how long an outbound hop may hang, and here it is also the bound on how long everything else waits. Token acquisition is single-flighted per client, so one caller makes the request and every other caller that missed the cache queues behind it — which turns a slow authorization server into a stalled application rather than one slow call. Without this the bound was HttpClient's own default of a hundred seconds, which is not a choice anybody made about a hop that exists to keep a fifteen-minute token fresh.

Ten seconds because that is what the two sibling outbound hops already use — the back-channel logout notification, per relying party, and the JAR request_uri fetch — and for the same reason they give: somebody is waiting on the answer. This is the third of the three and the only one whose delay is shared by every concurrent caller.

It bounds one request, so a caller that arrives while another holds the single-flight gate can wait up to twice it: once for the request in front of it, once for its own. A failing endpoint is worse than that, because a failure is deliberately not cached and each queued caller then tries in turn — so n waiting callers cost up to n times this value before the last of them hears about it. That is the gate's shape rather than this setting's, and it is recorded as its own work.