SAIF.NetCore.OIDC operations and processes¶
This page is the operation catalog and cross-operation hub for this library. Each operation's detailed, step-by-step logic lives in its own page under operations/.
Operation catalog¶
| Operation | Intent | Trigger | Inputs | Outputs | Rules |
|---|---|---|---|---|---|
| Configure cookie authentication | Build the "Cookies" named options: cookie attributes, data-protection ticket format, login-redirect event |
Options system builds the named CookieAuthenticationOptions (first use of "Cookies") |
IOidcSettings, IDataProtectionCertService, ILoginRedirectService |
Configured CookieAuthenticationOptions |
BR-OIDC-01, BR-OIDC-02, BR-OIDC-03, BR-OIDC-14, BR-OIDC-15, BR-OIDC-16 |
| Configure OpenID Connect | Build the "OpenIdConnect" named options: Okta authority, client credentials, token validation, state protection, redirect/failure events |
Options system builds the named OpenIdConnectOptions (first use of "OpenIdConnect") |
IOidcSettings |
Configured OpenIdConnectOptions |
BR-OIDC-01, BR-OIDC-04, BR-OIDC-05, BR-OIDC-06, BR-OIDC-07, BR-OIDC-08 |
| Before redirect to identity provider | Forward session/IdP hints and x-idp-* query parameters to the Okta authorize request |
OnRedirectToIdentityProvider event, during an OIDC challenge |
AuthenticationProperties, request query |
Augmented ProtocolMessage |
BR-OIDC-09 |
| Handle remote authentication failure | Classify and log an IdP failure, then redirect to login instead of showing an exception page | OnRemoteFailure event |
context.Failure |
Logged entry; 302 redirect with x-idp-err=se |
BR-OIDC-10, BR-OIDC-16 |
| Synchronize JWT values into claims and cookie | Keep id_token/access_token claims current and re-sign the auth cookie on every authenticated request |
JwtClaimMiddleware.InvokeAsync, every request |
HttpContext, current cookie principal |
Updated claims; re-issued cookie, or an exception | BR-OIDC-11, BR-OIDC-12 |
| Redirect expired sessions to token refresh | Detect an expired access token and short-circuit the pipeline with a redirect to the JwtRefresh app | RefreshJwtMiddleware.InvokeAsync, every request when enabled |
Cookie access_token/refresh_token |
301 redirect, or next |
BR-OIDC-13 |
| Resolve data-protection certificate | Find the LocalMachine\My certificate used to encrypt the data-protection key ring | Called from OP-01 step 2 | DPCertName |
A certificate, null (developer machine), or an exception |
BR-OIDC-14, BR-OIDC-15 |
| Redirect to login | Build and issue the HTTPS redirect to the login application, preserving the return URL | OnRedirectToLogin cookie event; OP-04 step 3 |
HttpContext, optional extra query parameters |
302 redirect | BR-OIDC-16, BR-OIDC-17, BR-OIDC-10 |
| Transform role claims | Map Okta group/role claim values onto ClaimTypes.Role, with a per-subject cache guard |
RoleClaimTransformer.TransformAsync, only if a consumer registers it as IClaimsTransformation |
Current ClaimsPrincipal |
Cloned principal with role claims added, or the original principal | BR-OIDC-18, BR-OIDC-19, BR-OIDC-20 |
| Role-transform cache | Track, per subject, how recently roles were transformed, to skip repeat work | Called from OP-09 steps 3 and 4 | Subject identifier | true/false; cache upsert |
BR-OIDC-21 |
| Resolve OIDC settings | Read every OIDC setting from the Environment API section NetCore_OIDC |
Property access on IOidcSettings, on demand throughout this library |
Environment API section NetCore_OIDC |
String, int, scope array, or credential value | BR-OIDC-22, BR-OIDC-04 |
| Refresh tokens against Okta | Exchange a refresh token for a new access/ID token pair at the Okta token endpoint | JwtRefreshService.Refresh, called by a consumer (for example, the JwtRefresh application) |
refreshToken, clientId/clientSecret |
JwtSet, or JwtRefreshException |
BR-OIDC-23, BR-OIDC-24, BR-OIDC-25 |
| Enforce URL casing | Permanently redirect mixed-case URLs to a lower-cased form | LowerCaseUrlMiddleware.InvokeAsync, every request |
Request scheme/host/path | 301 redirect, or next |
BR-OIDC-26 |
Process flow diagram¶
The following diagram visualizes the primary request-time flow across the thirteen operations.
flowchart TD
Challenge([OIDC/Cookie challenge]) --> OP01[Configure cookie authentication]
Challenge --> OP02[Configure OpenID Connect]
OP01 --> OP07[Resolve data-protection certificate]
OP02 --> OP11a[Resolve OIDC settings]
OP02 --> Redirect{Redirect to IdP?}
Redirect -->|Yes| OP03[Before redirect to identity provider]
OP03 --> Okta([Okta authorize/token endpoint])
Okta --> Failure{Remote failure?}
Failure -->|Yes| OP04[Handle remote authentication failure]
OP04 --> OP08[Redirect to login]
Failure -->|No| Authenticated([Authenticated session established])
Authenticated --> Request([Subsequent request])
Request --> CasingGate{Challenge type is OpenIdConnect?}
CasingGate -->|Yes| OP13[Enforce URL casing]
CasingGate -->|No| OP05
OP13 --> OP05[Synchronize JWT values into claims and cookie]
OP05 -->|failure| ErrorHandler([HttpContextAuthenticateException])
OP05 --> RefreshGate{UseJwtRefreshMiddleware enabled?}
RefreshGate -->|Yes| OP06[Redirect expired sessions to token refresh]
RefreshGate -->|No| PipelineContinues([Pipeline continues])
OP06 -->|expired| JwtRefreshApp([301 to external JwtRefresh application - request ends])
OP06 -->|valid| PipelineContinues
OP01 -.->|OnRedirectToLogin| OP08
OP11a -.-> OP01
OP11a -.-> OP02
OP11a -.-> OP06
subgraph Unwired["Not wired into the active pipeline<br>unless a consumer registers RoleClaimTransformer<br>as IClaimsTransformation"]
OP09[Transform role claims] --> OP10[Role-transform cache]
end
OP05 -.->|"only if registered as IClaimsTransformation -<br>not observed in any analyzed registration"| OP09
subgraph External["Separate, externally-triggered flow - no in-repo caller"]
OP12[Refresh tokens against Okta]
end
JwtRefreshApp -.->|downstream call, unknown/inferred| OP12
RefreshJwtMiddleware's 301 redirect ends the current request; it does not call JwtRefreshService.Refresh directly, so OP-12 is shown as a separate, externally-triggered flow whose caller is unknown/inferred** — not a verified continuation of this request. Likewise, Transform role claims and Role-transform cache are shown in a separate subgraph because RoleClaimTransformer is never invoked automatically unless a consumer registers it as IClaimsTransformation — no such registration was found in this repository (see Service registration).
Failure and edge-case behavior¶
- A missing or expired data-protection certificate is fatal on any non-developer machine (Resolve data-protection certificate); on a developer machine the cookie/OIDC-state key rings fall back to unencrypted storage.
- A malformed or missing
BOLAppCredentialssecure setting throws during OIDC options construction (Configure OpenID Connect step 2), before any OIDC request can be served. - A failed cookie re-authentication aborts the request with
HttpContextAuthenticateException(Synchronize JWT values into claims and cookie step 5); there is no built-in recovery path. - The
RoleClaimIdentitifier/RoleClaimIdentifierkey mismatch (see Configuration, CR-01) means Transform role claims can silently promote every non-array claim to a role, if and only if a consumer has registered the transformer at all. RefreshJwtMiddlewaredecodes the access token without signature validation before checking expiry (Redirect expired sessions to token refresh step 3); a malformed token is expected to throwArgumentException*.LowerCaseUrlMiddleware's mixed-case detection has a scheme/pathBase bug (see Enforce URL casing), and always callsnexteven after issuing a 301.
Related documentation¶
- Index
- Overview
- Architecture
- Dependencies
- Configuration
- Business rules
- Security and authorization
- Service registration
- API reference
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.csprojsrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Constants.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Contracts/RefreshTokenResult.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Exceptions/HttpContextAuthenticateException.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Exceptions/JwtRefreshException.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Exceptions/MissingDataProtectionCertificateException.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Extensions/ClaimsPrincipalExtensions.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Extensions/HttpContextExtensions.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/JwtClaimMiddleware.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/LowerCaseUrlMiddleware.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Middleware/RefreshJwtMiddleware.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureCookieAuthenticationOptions.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Options/ConfigureOpenIdConnectOptions.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/ClaimTransformationCacheService.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/DataProtectionCertService.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtAuthorizationCookieClaimService.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/JwtRefreshService.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/LoginRedirectService.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/OidcSettings.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/RoleClaimService.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/RoleClaimTransformer.cssrc/SAIF.NetCore.OIDC/src/SAIF.NetCore.OIDC/Services/UrlCaseService.cs