Skip to content

Register OIDC services

This operation registers the full set of OIDC-related middleware and services (claim synchronization, role transformation, JWT refresh, login redirects, data-protection certificates), then delegates to Add web authentication to configure the authentication schemes. It is used by App startup configure services when HostLocation == External.

Field Value
Operation ID OP-07
Trigger AppStartup.ConfigureServices (or a consumer) calls RegisterOidcServices(type = Cookie, useJwtRefreshMiddleware = true).
Inputs type — the authentication challenge type (Cookie or OpenIdConnect); useJwtRefreshMiddleware — whether IJwtRefreshService is registered in the service collection (this method performs DI registration only; it does not construct or alter the HTTP request pipeline).
Outputs OIDC middleware/services registered; web authentication schemes configured via OP-08.
Primary components IServiceCollectionExtensions.RegisterOidcServices
Entry point src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs (L137–168)

Steps

  1. Register Scoped JwtClaimMiddleware, LowerCaseUrlMiddleware, RefreshJwtMiddleware unconditionally (BR-SE-10)
  2. All three middleware types are registered in the container regardless of the useJwtRefreshMiddleware flag; that flag gates only the IJwtRefreshService registration in step 4. AppStartup separately passes its UseJwtRefreshMiddleware property into this parameter during service configuration and reads the same property again during Configure to decide whether to insert RefreshJwtMiddleware into the pipeline (see App startup configure pipeline). This registration method itself performs no pipeline insertion.

Origin: JwtClaimMiddleware's claim-synchronization logic is implemented in Sync JWT claims and LowerCaseUrlMiddleware's logic in Enforce URL casing (SAIF.NetCore.OIDC). 2. Register Singleton IOidcSettings → OidcSettings. OidcSettings's constructor only stores its injected IEnvironmentClient/ISystemHashService dependencies; it does not itself require or call a secure environment client, and most of its property/indexer getters read ordinary (non-secure) settings. Only the later AppCredentials getter needs a usable (non-null) ISystemHashService — see the failure section below (see Register secure environment client for how a secure ISystemHashService is registered).

Origin: Settings resolution logic is implemented in Resolve OIDC settings (SAIF.NetCore.OIDC); this step only registers the OidcSettings type. OidcSettings's constructor only stores its injected IEnvironmentClient/ISystemHashService dependencies — it performs no environment/secure-setting reads itself. Construction happens once, at first resolution of IOidcSettings. Each individual setting (for example DPCertName, CookieName) is instead fetched lazily, on every call to its corresponding property or indexer getter, which can happen many times after construction, not just once "at first resolution." 3. Register Scoped IUrlCaseService → UrlCaseService; Scoped RoleClaimTransformer; Scoped IRoleClaimService → RoleClaimService; Singleton IClaimTransformCacheService → ClaimTransformationCacheService; Transient ILoginRedirectService → LoginRedirectService.

Origin: Role-claim transformation and caching is implemented in Transform role claims and Role transform cache; login redirection in Redirect to login (SAIF.NetCore.OIDC). 4. If useJwtRefreshMiddleware: register Scoped IJwtRefreshService → JwtRefreshService (BR-SE-10)

Origin: Token refresh logic is implemented in Refresh tokens (SAIF.NetCore.OIDC); this step only registers the JwtRefreshService type, and its token-refresh logic runs later, at request time. 5. Register Scoped IJwtAuthorizationCookieClaimService → JwtAuthorizationCookieClaimService; Singleton IDataProtectionCertService → DataProtectionCertService.

Origin: Certificate resolution logic is implemented in Resolve DP certificate (SAIF.NetCore.OIDC); this step only registers the DataProtectionCertService type. Its constructor stores the injected IOidcSettings/ISaifLogService and immediately calls IEnvironmentClient.IsDeveloperMachine() at construction time (first resolution of IDataProtectionCertService) — it does not inject or resolve ISystemHashService directly. The actual certificate lookup is in GetCertificate(), which is not called during construction: it only runs when ConfigureCookieAuthenticationOptions.Configure(name, options) (an IConfigureNamedOptions<CookieAuthenticationOptions>) executes, which itself happens later, the first time the framework resolves named CookieAuthenticationOptions for the "Cookies" scheme (typically on the first request that evaluates cookie authentication), not during this registration call or during DataProtectionCertService construction. 6. Call AddWebAuthentication(type), a same-library registration operation that is executed synchronously as part of this call (BR-SE-11): it registers ConfigureOptions<ConfigureCookieAuthenticationOptions>()/ConfigureOptions<ConfigureOpenIdConnectOptions>() (deferred IConfigureOptions<CookieAuthenticationOptions>/IConfigureOptions<OpenIdConnectOptions>, each applied later, only the first time the framework resolves that named-scheme options instance), calls AddAuthentication(options => ...) to set DefaultAuthenticateScheme = DefaultSignInScheme = "Cookies" and DefaultChallengeScheme = "OpenIdConnect" if type == OpenIdConnect else "Cookies", then .AddCookie("Cookies").AddOpenIdConnect() to register both handlers regardless of which one is the default challenge scheme.

Origin: AddWebAuthentication(type)'s full step-by-step registration behavior (the exact deferred-configurator and scheme-default wiring summarized above) is documented on Add web authentication (same library, IServiceCollectionExtensions.AddWebAuthentication); unlike the OIDC registrations in steps 1–5, this call executes immediately, synchronously, as part of RegisterOidcServices itself — it is not deferred to first resolution.

Process flow

This diagram shows the one-time DI registration sequence performed when RegisterOidcServices(type, useJwtRefreshMiddleware) is called during service configuration, including the synchronous AddWebAuthentication(type) delegation in the final step; it does not depict per-request middleware/claim-transformation behavior.

flowchart TD
    Start([RegisterOidcServices called]) --> S1[Register OIDC middleware]
    S1 --> S2[Register IOidcSettings]
    S2 --> S3[Register role-claim / login-redirect services]
    S3 --> S4{useJwtRefreshMiddleware?}
    S4 -->|Yes| S4a[Register IJwtRefreshService]
    S4 -->|No| S5[Register cookie-claim / data-protection cert services]
    S4a --> S5
    S5 --> S6[AddWebAuthentication]
    S6 --> EndOk([OIDC services registered])

Failure and edge-case behavior

  • Resolving IOidcSettings itself never requires a secure environment client: OidcSettings's constructor only stores its injected IEnvironmentClient/ISystemHashService dependencies. The secure-client requirement is lazy and property-specific — only the AppCredentials getter later calls _systemHashService.ComputeHash(SystemType.Other, Assembly.GetExecutingAssembly().GetName().Name) (OIDC's own executing assembly, not the caller's) and _environmentClient.GetSecureSetting(Constants.AppCredentialsKey, Constants.EnvironmentSection, hash), so registering RegisterOidcServices without a prior secure environment-client registration (a null-hash ISystemHashService) only fails the first time code reads OidcSettings.AppCredentials — for example from ConfigureOpenIdConnectOptions — not at IOidcSettings resolution or construction. Every other OidcSettings property/indexer getter reads an ordinary (non-secure) setting and does not require a secure client (see BR-SE-01).

Sources

  • src/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/SAIF.NetCore.ServiceExtensions/IServiceCollectionExtensions.cs