Skip to content

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 BOLAppCredentials secure 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/RoleClaimIdentifier key 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.
  • RefreshJwtMiddleware decodes the access token without signature validation before checking expiry (Redirect expired sessions to token refresh step 3); a malformed token is expected to throw ArgumentException*.
  • LowerCaseUrlMiddleware's mixed-case detection has a scheme/pathBase bug (see Enforce URL casing), and always calls next even after issuing a 301.

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