Skip to content

SAIF.NetCore.OIDC business rules

This page captures business rules enforced by this library.

BR-OIDC-01 Option configurators apply only to their named scheme

Field Value
Statement Option configurators apply only to the named schemes "Cookies" and "OpenIdConnect".
Trigger Options build.
Enforcement ConfigureCookieAuthenticationOptions.Configure(string name, CookieAuthenticationOptions options) L49–92; ConfigureOpenIdConnectOptions.Configure(string name, OpenIdConnectOptions options) L50–104.
Outcome Other scheme names receive no change.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureCookieAuthenticationOptions.cs; src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cs

Field Value
Statement The auth cookie is HttpOnly, Essential, SameSite=Lax, Path "/", has sliding expiration, and expires after CookieExpireMinutes. The Secure policy is not enforced.
Trigger Cookie options build.
Enforcement ConfigureCookieAuthenticationOptions.Configure.
Outcome Cookie attributes are set as stated; Cookie.SecurePolicy defaults to SameAsRequest.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureCookieAuthenticationOptions.cs

Field Value
Statement Cookie tickets are protected with a file-system key ring at DPKeyDirectory, app name DPApplicationName, and the key ring is encrypted by the DP certificate when one exists.
Trigger Cookie options build.
Enforcement ConfigureCookieAuthenticationOptions.Configure.
Outcome Shared-key cookie across apps with the same app name and directory*.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureCookieAuthenticationOptions.cs

BR-OIDC-04 OIDC client credentials come from a secure, library-hashed setting

Field Value
Statement OIDC client credentials come from secure setting NetCore_OIDC.BOLAppCredentials (hash of SystemType.Other + "SAIF.NetCore.OIDC") and must be clientId\|clientSecret.
Trigger AppCredentials get.
Enforcement OidcSettings.AppCredentials; OidcAppCredentials..ctor (ServiceContracts).
Outcome Exceptions on a missing or malformed value.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/OidcSettings.cs

BR-OIDC-05 Inbound JWT claim names are not remapped

Field Value
Statement Inbound JWT claim names are not remapped (the global map is cleared).
Trigger OIDC options build.
Enforcement ConfigureOpenIdConnectOptions.Configure.
Outcome Raw claim types (sub, name) are preserved process-wide.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cs

BR-OIDC-06 OIDC uses the authorization-code flow against Okta

Field Value
Statement OIDC uses the authorization-code flow against authority OktaBaseUrl+OktaAuthorizationServerUrl, with HTTPS metadata, userinfo claims, saved tokens, and the session lifetime decoupled from token lifetime (UseTokenLifetime=false).
Trigger OIDC options build.
Enforcement ConfigureOpenIdConnectOptions.Configure.
Outcome Handler configured for the authorization-code flow.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cs

BR-OIDC-07 ID tokens must pass full validation

Field Value
Statement ID tokens must be signed, unexpired (clock skew ClockSkewSeconds), issued by the authority, and have audience = ClientId. Role claim type = ClaimTypes.Role; name claim = name.
Trigger Token validation.
Enforcement ConfigureOpenIdConnectOptions.Configure (TokenValidationParameters) + Okta StrictSecurityTokenValidator.
Outcome An invalid token results in a remote failure (OP-04).
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cs

BR-OIDC-08 OIDC correlation state uses an unencrypted key ring

Field Value
Statement OIDC correlation/nonce state is protected with the app name {DPApplicationName}-oidc in DPKeyDirectory, without certificate encryption.
Trigger OIDC options build.
Enforcement ConfigureOpenIdConnectOptions.Configure L93–95.
Outcome Unencrypted key ring for OIDC state.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cs

BR-OIDC-09 Session/IdP hints and x-idp wildcard parameters are forwarded to Okta

Field Value
Statement sessionToken, idp, login_hint auth properties and any x-idp-* query parameters are forwarded to the IdP authorize request.
Trigger Challenge.
Enforcement ConfigureOpenIdConnectOptions.BeforeRedirectToIdentityProviderAsync.
Outcome Okta receives the forwarded hints.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cs

BR-OIDC-10 Remote auth failures are classified, logged, then redirected

Field Value
Statement Remote auth failures are logged as Warning for correlation/state errors and Error otherwise, then redirected to the login page with x-idp-err=se.
Trigger OnRemoteFailure.
Enforcement ConfigureOpenIdConnectOptions.OnRemoteFailureAsync.
Outcome A friendly redirect is issued; no exception page is shown.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cs

Field Value
Statement For authenticated requests, a failed cookie re-authentication aborts the request with HttpContextAuthenticateException.
Trigger Authenticated request.
Enforcement JwtClaimMiddleware.InvokeAsync.
Outcome An exception is thrown.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/JwtClaimMiddleware.cs

Field Value
Statement id_token and access_token are mirrored as claims (one per type, replaced on update), and the cookie is re-signed on every authenticated request.
Trigger Authenticated request.
Enforcement JwtAuthorizationCookieClaimService.UpdateJwtTokenValues; ClaimsPrincipalExtensions.AddUpdateClaim.
Outcome Claims and cookie are refreshed.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtAuthorizationCookieClaimService.cs

BR-OIDC-13 An expired access token short-circuits the pipeline

Field Value
Statement An expired access token (ValidTo < UtcNow, unvalidated decode) triggers a 301 redirect to RefreshTokenRedirectUrl, carrying the refresh token and origin in the query.
Trigger Authenticated request with refresh middleware enabled.
Enforcement RefreshJwtMiddleware.InvokeAsync.
Outcome The pipeline is short-circuited.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/RefreshJwtMiddleware.cs

BR-OIDC-14 Data-protection certificate must match subject and validity window

Field Value
Statement The DP certificate is the LocalMachine\My cert whose Subject equals DPCertName exactly and is currently within its validity window.
Trigger Certificate lookup.
Enforcement DataProtectionCertService.GetCertificate.
Outcome A matching certificate, or none.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/DataProtectionCertService.cs

BR-OIDC-15 A missing DP certificate is fatal outside developer machines

Field Value
Statement A missing DP certificate is fatal outside developer machines. Developer machines continue without key encryption.
Trigger Certificate lookup.
Enforcement DataProtectionCertService.GetCertificate.
Outcome MissingDataProtectionCertificateException, or null on a developer machine.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/DataProtectionCertService.cs

BR-OIDC-16 Login redirects always use HTTPS on the current host

Field Value
Statement Login redirects always use HTTPS on the current host: https://{host}{CookieLoginPath}{CookieSigninUri}.
Trigger Login challenge / remote failure.
Enforcement LoginRedirectService.Redirect.
Outcome A 302 redirect is issued.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/LoginRedirectService.cs

BR-OIDC-17 The origin query parameter is conditionally added from the already-built login URL

Field Value
Statement The already-constructed login-redirect URL's own query string (not the incoming request's query string) is checked for a non-whitespace origin value; origin = PathBase+Path+QueryString of the current request is added only when that constructed URL's query lacks origin and the current request path does not start with CookieLoginPath. No content or safety validation of the origin value itself is performed.
Trigger Login redirect.
Enforcement LoginRedirectService.Redirect.
Outcome The return URL is preserved in most cases (the freshly-built URL's query is normally empty), without re-adding origin when under CookieLoginPath.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/LoginRedirectService.cs

BR-OIDC-18 A role claim is created for every matching, non-array claim

Field Value
Statement A role claim is created for every claim whose lowercased type contains RoleClaimIdentifier and whose value contains no [.
Trigger Claims transformation.
Enforcement RoleClaimService.AddRoleClaims.
Outcome Roles are added to a cloned principal.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/RoleClaimService.cs

BR-OIDC-19 Role transformation is skipped when roles already exist and are cached

Field Value
Statement Role transformation is skipped when the principal already has a role claim and the subject is cached.
Trigger Claims transformation.
Enforcement RoleClaimService.AddRoleClaims.
Outcome The original principal is returned.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/RoleClaimService.cs

BR-OIDC-20 Array-valued role claims are ignored

Field Value
Statement Array-valued role claims (serialized with [) are ignored; only flattened values become roles.
Trigger Claims transformation.
Enforcement RoleClaimService.AddRoleClaims.
Outcome No role is added for array-valued claims.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/RoleClaimService.cs

BR-OIDC-21 Transformed roles are considered fresh for a configurable offset

Field Value
Statement A subject's transformed roles are considered fresh for RoleTransformCacheOffset seconds (local time); stale entries are evicted on lookup.
Trigger Cache lookup.
Enforcement ClaimTransformationCacheService.Exists/Cache.
Outcome true/false, with stale entries removed.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/ClaimTransformationCacheService.cs

BR-OIDC-22 All OIDC settings are read from the NetCore_OIDC section

Field Value
Statement All OIDC settings are read from Environment API section NetCore_OIDC. Missing string settings resolve to "", missing int settings throw.
Trigger Property access.
Enforcement OidcSettings.
Outcome A string default, or an exception for missing int settings.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/OidcSettings.cs

BR-OIDC-23 A token refresh POSTs to a composed Okta endpoint with Basic auth

Field Value
Statement A token refresh POSTs to {OktaBaseUrl}{OktaAuthorizationServerUrl}{RefreshTokenUrl}{RefreshTokenQueryString}{refreshToken} with Basic client authentication.
Trigger Refresh call.
Enforcement JwtRefreshService.Refresh.
Outcome An Okta token response is returned.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtRefreshService.cs

BR-OIDC-24 A non-successful refresh raises a typed exception

Field Value
Statement A non-successful refresh response raises JwtRefreshException carrying the HTTP status.
Trigger Refresh failure.
Enforcement JwtRefreshService.Refresh.
Outcome An exception is thrown.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtRefreshService.cs

BR-OIDC-25 Refreshed expiry is computed from expires_in; rotation is discarded

Field Value
Statement The refreshed ExpiresAt = UtcNow + expires_in seconds. A rotated refresh token is not returned.
Trigger Refresh success.
Enforcement JwtRefreshService.Refresh.
Outcome A JwtSet is returned.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtRefreshService.cs

BR-OIDC-26 Mixed-case URLs are permanently redirected to lower case

Field Value
Statement Mixed-case URLs are permanently (301) redirected to the lower-cased scheme/host/path, preserving the query string.
Trigger External-host request.
Enforcement UrlCaseService.EnforceCasing; LowerCaseUrlMiddleware.InvokeAsync.
Outcome A 301 is issued and the pipeline continues.
Source src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/UrlCaseService.cs; src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/LowerCaseUrlMiddleware.cs

Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.

Sources

  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/SAIF.NetCore.OIDC.csproj
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Constants.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Contracts/RefreshTokenResult.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Exceptions/HttpContextAuthenticateException.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Exceptions/JwtRefreshException.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Exceptions/MissingDataProtectionCertificateException.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Extensions/ClaimsPrincipalExtensions.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Extensions/HttpContextExtensions.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/JwtClaimMiddleware.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/LowerCaseUrlMiddleware.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/RefreshJwtMiddleware.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureCookieAuthenticationOptions.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/ClaimTransformationCacheService.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/DataProtectionCertService.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtAuthorizationCookieClaimService.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtRefreshService.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/LoginRedirectService.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/OidcSettings.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/RoleClaimService.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/RoleClaimTransformer.cs
  • src/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/UrlCaseService.cs