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
BR-OIDC-02 Cookie attributes are fixed; Secure policy is not enforced
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
BR-OIDC-03 Cookie tickets are protected by a shared file-system key ring
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
BR-OIDC-11 A failed cookie re-authentication aborts the request
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
BR-OIDC-12 JWT claims and the cookie are refreshed on every request
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
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
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