Authorization Server — Authentication Flows
Step-by-step flows the MibAuthorizationServer implements, with sequence diagrams. For the components referenced here (endpoints, schemes, stores, keys), see AuthorizationServerOverview.md.
All flows run on OpenIddict 5.8.0. Access tokens are reference (opaque) tokens validated locally against AUTH_GRANTS.
1. Interactive login + Authorization Code (browser / React UI)
Used by MibServer3 (BFF) to log a human in. The user's credentials are never exposed to the BFF — only the authorization code and tokens are.
sequenceDiagram
autonumber
participant U as Browser
participant BFF as MibServer3 (BFF)
participant AUTH as Auth Server :8601
participant SPA as React Auth UI
participant DB as DB (AUTH_GRANTS / users)
U->>BFF: open protected page
BFF-->>U: 302 → /oauth/authorize?client_id&redirect_uri&scope
U->>AUTH: GET /oauth/authorize
Note over AUTH: no Cookies session yet
AUTH-->>U: Challenge(Cookies) → 302 to React /login?returnUrl=/oauth/authorize…
U->>SPA: load login UI
SPA->>AUTH: POST /api/v2/auth/login (username, password, returnUrl)
Note over AUTH: LoginWorkflow.VerifyCredentials<br/>(may require password change / TOTP step)
AUTH->>DB: validate user, write ADM_USER_LOGIN_HISTORY
AUTH-->>SPA: 200 (LoginFinalizer issued Cookies session)
SPA-->>U: navigate back to returnUrl (/oauth/authorize…)
U->>AUTH: GET /oauth/authorize (now with Cookies session)
Note over AUTH: Connect/AuthorizationController<br/>builds principal, auto-consent (UseNewLoginUI)
AUTH->>DB: Upsert authorization (AUTH_GRANTS)
AUTH-->>U: 302 redirect_uri?code=…
U->>BFF: GET /oauth/callback?code=…
BFF->>AUTH: POST /oauth/token (code, client_id, client_secret, redirect_uri)
AUTH-->>BFF: access (reference) + refresh token
BFF-->>U: authenticated session
Key points:
- The login step (
/api/v2/auth/login) only establishes the Cookies session on the auth server; it does not issue OAuth tokens.LoginFinalizerbuilds the cookieClaimsPrincipal(subject + name + roles) and records the login inADM_USER_LOGIN_HISTORY. - The authorization code is issued by
Connect/AuthorizationControlleronly once a valid Cookies session exists; consent is automatic for first-party clients (useNewLoginUI=true). - Multi-step login (password expired/change, TOTP) is handled by
LoginWorkflow+LoginStepResultHandlerbefore the session is finalized — see PasswordChangeFlowsOperation.md and TwoFactorAuthenticationFlows.md.
2. Resource Owner Password Credentials (ROPC)
Used by APIs (MibServerApi, File Management, the Auth Server itself) that authenticate with a username/password directly. OAUTH_CLIENT_TYPE = 3.
sequenceDiagram
autonumber
participant API as API client
participant AUTH as Auth Server :8601
participant DB as DB
API->>AUTH: POST /oauth/token<br/>grant_type=password, username, password, client_id, client_secret, scope
Note over AUTH: PasswordGrantTokenHandler
AUTH->>DB: validate client secret (plain text) + user credentials
alt valid
AUTH-->>API: 200 access (reference) [+ refresh if offline_access]
else bad client
AUTH-->>API: 400 invalid_client
else blocked user
AUTH-->>API: 400 unauthorized_client
end
3. Client Credentials
Service-to-service authentication with no user context.
sequenceDiagram
autonumber
participant SVC as Service client
participant AUTH as Auth Server :8601
SVC->>AUTH: POST /oauth/token<br/>grant_type=client_credentials, client_id, client_secret, scope
Note over AUTH: ClientCredentialsTokenHandler
AUTH-->>SVC: 200 access (reference), no refresh token
4. Refresh token rotation
sequenceDiagram
autonumber
participant C as Client
participant AUTH as Auth Server :8601
participant DB as AUTH_GRANTS
C->>AUTH: POST /oauth/token<br/>grant_type=refresh_token, refresh_token, client_id, client_secret
Note over AUTH: RefreshTokenGrantHandler<br/>re-evaluates user IsActive
AUTH->>DB: rotate (revoke old, issue new)
AUTH-->>C: 200 new access + new refresh
C->>AUTH: reuse the OLD refresh token
AUTH-->>C: 400 invalid_grant
- Default model is one-time-use (rolling) refresh tokens with zero reuse leeway — reusing a rotated token fails with
invalid_grant. - Set
reuseRefreshToken=trueinMibIdentityConfigto allow reuse (rolling disabled). Absolute vs sliding expiration is controlled byslidingRefreshTokenExpiration. See Configuration.
5. Protected resource request (reference-token validation)
How a request bearing a reference access token is authorized on a protected endpoint (e.g. ApiV1Controller, ApiV2BaseController, UserController).
sequenceDiagram
autonumber
participant C as Caller
participant EP as Protected endpoint<br/>[Authorize(MibApiProtection)]
participant V as OpenIddict Validation<br/>(UseLocalServer)
participant DB as AUTH_GRANTS
C->>EP: request + Authorization: Bearer <reference token>
EP->>V: policy scheme forwards to validation
V->>DB: look up reference token, check status + expiration
alt valid
V-->>EP: ClaimsPrincipal (subject, client, scopes)
EP-->>C: 200
else missing/invalid/revoked
EP-->>C: 401
end
The BFF's "current user" lookup (
UserController.Me_AllowAnonymous, called with?access_token=) validates the reference token through the nativeIReferenceTokenValidator(introduced when the IdentityServer4ITokenValidatoradapter was removed) rather than the[Authorize]pipeline.
6. Logout
sequenceDiagram
autonumber
participant U as Browser
participant AUTH as Auth Server :8601
participant DB as AUTH_GRANTS
U->>AUTH: GET /logout?redirect_uri=…
AUTH->>AUTH: sign out Cookies session, clear server-side session id
AUTH->>DB: IUserGrantRevoker.RemoveAllAsync(subject, client)<br/>revoke tokens + authorizations
AUTH-->>U: 302 redirect_uri (or login page)
After logout the revoked reference tokens no longer pass validation (flow 5 returns 401).
Who supplies redirect_uri (MEDIAIBOX-12282). The auth server redirects to it verbatim, so a relative value would resolve against the auth server's own origin — the caller must send an absolute URL. The CMS front-end server's /auth/logout builds it: a returnUrl on the request is honoured when it is a same-origin CMS page, and a sign-out that names no destination — which is every sign-out from the SPA's account menu — resolves to the CMS SPA root (FrontendAppPath, falling back to /app/). It previously fell back to RootUrl, which serves the legacy interface, so an operator signing out of the SPA signed back in to the legacy UI. Recovery from an expired session is a different flow and still returns the operator to the page they were interrupted on.
7. Key bootstrap (startup)
On startup BootstrapOpenIddictKeysAsync ensures the signing key (AUTH_SIGNING_CREDENTIALS / AUTH_VALIDATION_KEYS) and the encryption key (AUTH_ENC_CREDENTIALS) exist, creating them on first run. The encryption key must persist across restarts; otherwise existing refresh tokens and authorization codes (JWE-encrypted) become undecryptable and every user must re-authenticate. See AuthorizationServerOverview.md.