Authorization Server — Architecture Overview
This document explains how the MibAuthorizationServer works internally: the OAuth/OIDC engine, the components, the endpoints, the token model, the database mapping and where each piece lives in the code. It is meant both as an onboarding entry point and as maintenance context.
For installation and the IdentityServer4 → OpenIddict upgrade, see AuthorizationServerInstallation.md. For client/token configuration keys, see AuthorizationServerConfiguration.md. For step-by-step request flows with sequence diagrams, see AuthorizationServerAuthenticationFlows.md.
What it is
MibAuthorizationServer (port 8601 by default) is the MIB platform's OAuth 2.0 / OpenID Connect provider. It authenticates users and services and issues tokens consumed by the rest of the platform (MibServer3/BFF, MibServerApi, microservices). It also hosts the user-administration pages and the password/2FA flows.
The OAuth/OIDC engine is OpenIddict 5.8.0 on .NET 8. It previously ran on IdentityServer4 (v3.1.4, EOL), which has been fully removed (see MEDIAIBOX-11999). The migration preserved the database schema, endpoints, grant types, RS512 signing and reference (opaque) access tokens, so the change is transparent to most clients.
High-level architecture
flowchart TB
subgraph Clients
SPA["React Auth UI"]
BFF["MibServer3 / BFF"]
API["MibServerApi and microservices"]
end
subgraph AuthServer["MibAuthorizationServer :8601"]
direction TB
subgraph OpenIddict
Server["AddServer<br/>token / authorize / userinfo"]
Validation["AddValidation<br/>local reference-token introspection"]
Core["AddCore<br/>custom stores and managers"]
end
Login["Interactive login pipeline<br/>api/v2/auth + Connect/AuthorizationController"]
Keys["MibKeyProvider<br/>signing and encryption keys"]
end
DB[("SQL Server<br/>API_CLIENTS, AUTH_GRANTS,<br/>AUTH_*_CREDENTIALS, AUTH_VALIDATION_KEYS,<br/>ADM_USER_LOGIN_HISTORY, users")]
SPA --> Login
BFF -->|"/oauth/authorize, /oauth/token"| Server
API -->|"/oauth/token ROPC and client_credentials"| Server
BFF -->|"Bearer reference token"| Validation
Core --> DB
Login --> DB
Keys --> DB
The OpenIddict engine
Configured in ConfigureMibAuth.SetupOpenIddict (MediaiBox.Cms.Authorization.Server/AppStart/ConfigureMibAuth.cs) as three cooperating parts:
AddCore — persistence over the existing schema
OpenIddict's stores are replaced by custom stores that read/write the current MIB tables (no EF entities, no data migration):
| OpenIddict concept | Custom type | Backing table |
|---|---|---|
| Application (client) | MibApplicationStore / MibApplicationManager |
API_CLIENTS |
| Authorization (grant) | MibAuthorizationStore |
AUTH_GRANTS |
| Token | MibTokenStore |
AUTH_GRANTS |
| Scope | MibScopeStore |
(static set, see below) |
MibApplicationManager overrides ValidateClientSecretAsync to compare the plain-text secret stored in API_CLIENTS.OAUTH_CLIENT_SECRET (secret hashing is intentionally out of scope of the migration). The store getters never throw NotImplementedException because OpenIddict's manager cache calls them.
An authorization and its tokens share the
AUTH_GRANTStable; the authorization row is distinguished by a sentinel value"openiddict-authorization".
AddServer — issuing tokens
- Endpoints (see the reference table below) — both the historical
/oauth/*paths and the OpenIddict-native/connect/*paths are registered. - Scopes:
openid,email,profile,offline_access,mibapi. - Grants:
authorization_code,password(ROPC),client_credentials,refresh_token. - Reference (opaque) access tokens (
UseReferenceAccessTokens). Access-token JWE is disabled, but OpenIddict 5.x still encrypts refresh tokens and authorization codes as JWE — hence the mandatory encryption key (see Keys). - Rolling refresh tokens with zero reuse leeway by default (
SetRefreshTokenReuseLeeway(TimeSpan.Zero)); the absolute/sliding and reuse/one-time model is read fromMibIdentityConfig(ConfigureRefreshTokenModel). - Grant handlers (scoped event handlers on
HandleTokenRequestContext):ClientCredentialsTokenHandler,PasswordGrantTokenHandler,RefreshTokenGrantHandler. - Parity handlers:
InvalidClientResponseCodeHandler(maps OpenIddict's401on bad client to IdentityServer4's400 invalid_client),AuthorizationErrorRedirectHandler(authorize-endpoint error redirect). - ASP.NET passthrough is enabled for the authorize and userinfo endpoints, so they are served by MVC controllers (
Connect/AuthorizationController,Connect/UserInfoController) instead of OpenIddict's built-in handlers.
AddValidation — protecting resources
UseLocalServer() + UseAspNetCore(): the server validates its own reference tokens locally (no network introspection). This backs the MibApiProtection scheme (below).
Authentication schemes
Wired in Program.cs:
| Scheme | Purpose |
|---|---|
Cookies (default) |
Interactive browser session created after login; consumed by the authorize endpoint to issue the authorization code. Cookie is protected with MibAesProtector; for /api/* paths a missing/expired session returns 401/403 instead of redirecting. |
MibApiProtection (MibAuthSchemes.ApiProtection) |
A policy scheme that forwards to the OpenIddict validation scheme. Applied via [Authorize(AuthenticationSchemes = MibAuthSchemes.ApiProtection)] on ApiV1Controller, ApiV2BaseController and UserController to protect them with a reference access token. |
| OpenIddict Validation | The actual reference-token validator the policy scheme forwards to. Also used directly by Connect/UserInfoController. |
Keys
MibKeyProvider (MediaiBox.Cms.Authorization.MibIdentity/Stores/OpenIddict/MibKeyProvider.cs) owns three key materials, persisted in the database and bootstrapped on first start (BootstrapOpenIddictKeysAsync in Program.cs):
| Key | Algorithm | Table | Notes |
|---|---|---|---|
| Signing | RS512 | AUTH_SIGNING_CREDENTIALS |
Token signature; the public key is published at the JWKS endpoint. Stable across the migration. |
| Validation | RS512 | AUTH_VALIDATION_KEYS |
Validation key(s). |
| Encryption | AES-256 (Aes256KW / Aes256CbcHmacSha512) |
AUTH_ENC_CREDENTIALS |
New. Encrypts refresh tokens and authorization codes (JWE). Must persist across restarts — an ephemeral key invalidates all live refresh tokens/codes on every restart. |
OpenIddictKeyConfiguration (an IConfigureOptions<OpenIddictServerOptions>) injects the signing and encryption credentials into the server options at startup.
Endpoints
| Purpose | Path(s) |
|---|---|
| Discovery | /.well-known/openid-configuration |
| JWKS | /.well-known/openid-configuration/jwks |
| Token | /oauth/token, /connect/token |
| Authorize | /oauth/authorize, /connect/authorize |
| Userinfo | /connect/userinfo |
| Introspection | /connect/introspect |
| Revocation | /connect/revocation |
| End session (logout) | /connect/endsession |
| Interactive login (React) | POST /api/v2/auth/login, /update-password, /totp, /forgot-password, /reset-password |
| Interactive logout | /logout |
The
/oauth/tokenand/oauth/authorizepaths come fromMibAuthorizationServerConfig(tokenEndpoint/authorizeEndpoint) and default to those values; both they and the/connect/*aliases resolve to the same handlers.
Path-prefix deployments: when the server runs under a URL sub-path (
customUrlBase, e.g./MibAuth), every functional endpoint above is also registered under that prefix (/MibAuth/oauth/authorize,/MibAuth/connect/token, …) so it is reachable through the reverse proxy; the bare paths stay registered for same-origin and internal service-to-service callers. The discovery document is served at{prefix}/.well-known/openid-configurationand reflects the prefix. See Installation › Deploying under a URL sub-path.
Token model
- Access token: reference (opaque) string; validated locally by the validation handler against
AUTH_GRANTS. LifetimeAccessTokenLifetime(default 3600 s). - Refresh token: issued when
offline_accessis requested. Rolling (one-time) by default; absolute vs sliding expiration and reuse vs one-time are configurable (see Configuration). Encrypted as JWE. - Authorization code: short-lived (default 300 s), encrypted as JWE.
- Token cleanup: an optional hosted service (
OpenIddictTokenPruningService, enabled viatokenCleanUpServiceEnabled) prunes expired grants fromAUTH_GRANTS.
Database tables
| Table | Used for |
|---|---|
API_CLIENTS |
OAuth clients (id, plain-text secret, grant type, redirect URI). OAUTH_CLIENT_TYPE: 1 = authorization code, 3 = ROPC. |
AUTH_GRANTS |
Authorizations and tokens (reference access, refresh, codes). |
AUTH_SIGNING_CREDENTIALS |
RS512 signing key. |
AUTH_VALIDATION_KEYS |
Validation keys. |
AUTH_ENC_CREDENTIALS |
New — AES-256 token/code encryption key. |
ADM_USER_LOGIN_HISTORY |
Login audit trail (IP, user agent, client id, outcome). |
| user/account tables | Credentials, roles, 2FA/Latch/TOTP, preferences. |
Code map (for maintenance)
| Area | Location |
|---|---|
| Engine wiring, schemes, keys, lifetimes | MediaiBox.Cms.Authorization.Server/AppStart/ConfigureMibAuth.cs, Program.cs |
| Grant handlers | …/Server/AppStart/{ClientCredentials,PasswordGrant,RefreshTokenGrant}…Handler.cs |
| Authorize / userinfo controllers | …/Server/Controllers/Connect/ |
| Interactive login API | …/Server/Controllers/Api/AuthenticationV2Controller.cs + …/Helper/Authentication/ (LoginFinalizer, IAuthorizationContextParser, IReferenceTokenValidator, IUserGrantRevoker) |
| Custom stores / managers / key provider | MediaiBox.Cms.Authorization.MibIdentity/Stores/OpenIddict/ |
| Token lifetime / refresh config | MediaiBox.Cms.Authorization.MibIdentity/Config/MibIdentityConfig.cs |
| Server-level config | MediaiBox.Cms.Authorization.Model/Config/MibAuthorizationServerConfig.cs |
Security notes
- Client secrets are stored and compared in plain text in
API_CLIENTS. Hashing is a tracked follow-up, not part of the current engine. - Forced re-login on engine change: grants serialized by IdentityServer4 are not readable by OpenIddict, so the cutover invalidates all live tokens once. This is the documented migration path (no compatibility shim).
- Consent is automatic/inline for first-party clients when
useNewLoginUI=true; there is no consent screen.
Related documentation
- AuthorizationServerInstallation.md — install, DB migration, upgrade ToDo.
- AuthorizationServerConfiguration.md — client registration, token lifetimes, keys.
- AuthorizationServerAuthenticationFlows.md — sequence diagrams per flow.
- 2FA / password: TwoFactorAuthenticationFlows.md, TotpPairingFlows.md, PasswordChangeFlowsOperation.md, LockServer.md.