Skip to main content
Every HTTP request to the MDCMS server passes through a layered middleware chain before reaching a route handler. This page documents the full request flow, authentication mechanisms, RBAC model, API key scopes, and response envelope format.

Middleware Chain

The server processes each request through the following stages, in order.

Authentication Flows

MDCMS supports three authentication mechanisms, each designed for a different client context.

API Key Authentication

API keys are intended for server-to-server communication, CI/CD pipelines, and SDK usage.
  • Keys use a mdcms_key_ prefix for easy identification in logs.
  • The key value is hashed (SHA-256) before storage — the raw key is only shown once at creation time.
  • Each key carries an array of operation scopes (e.g., content:read, schema:write) and a context allowlist restricting which project/environment pairs it can access.
  • Keys support optional expiration via expiresAt and soft revocation via revokedAt.

Session Authentication

Sessions are used by the Studio UI and browser-based interactions.
  • Created via better-auth after successful password, OIDC, or SAML authentication.
  • Stored in the sessions table with a session token cookie.
  • Inactivity timeout: 7 days of no activity expires the session.
  • Absolute max age: 30 days regardless of activity.
  • CSRF protection: Mutations require a X-MDCMS-CSRF-Token header matching the mdcms_csrf cookie (24-byte random token).
  • Supported identity providers: password (credential), OIDC (Okta, Azure AD, Google Workspace, Auth0), SAML.

CLI Device Flow

The CLI authenticates via a device-authorization-like flow:
1

Challenge creation

The CLI creates a login challenge with a 10-minute TTL, specifying the target project, environment, redirect URI, and requested scopes.
2

Browser authorization

The user opens a browser URL, authenticates via session (password/OIDC/SAML), and authorizes the CLI challenge. The challenge status transitions from pending to authorized.
3

Code exchange

The CLI polls for the authorization code, exchanges it for a scoped API key, and stores the credentials locally. The challenge status transitions from authorized to exchanged.
Default CLI login scopes: content:read, content:read:draft, content:write, content:delete, schema:read, schema:write.

RBAC Model

MDCMS implements role-based access control with hierarchical scoping.

Roles

Roles form an ordered hierarchy. Higher roles inherit all capabilities of lower roles.
admin and owner roles are restricted to global scope by a database check constraint. They cannot be scoped to a specific project or folder prefix.

Scopes

Each RBAC grant is bound to a scope that determines where the role applies:

Role Capability Matrix

API Key Scopes

API keys use a fine-grained scope model independent of RBAC roles. Each key declares which operations it is permitted to perform.
API keys are scoped to specific project/environment pairs via the contextAllowlist. A key with content:read scope but an allowlist of [{project: "docs", environment: "production"}] cannot read content from any other project or environment.

Response Envelopes

All API responses use one of three standard envelope formats.

Single Resource

Paginated Collection

Error

Error responses always include a machine-readable code, a human-readable message, and an ISO-8601 timestamp. The optional details object provides context-specific debugging information. The requestId is echoed from the X-Request-Id header when present.

CORS Configuration

Studio browser routes (content, schema, media, auth, search, webhooks, actions, environments, collaboration, and Studio bootstrap) are protected by origin validation. Configure allowed origins via the MDCMS_STUDIO_ALLOWED_ORIGINS environment variable:
The server validates that the Origin header matches either the request’s own origin (same-origin) or one of the configured allowed origins. Requests from disallowed origins receive a 403 FORBIDDEN_ORIGIN response. Preflight OPTIONS requests are handled automatically with the appropriate access-control-allow-* headers.
In local development, the default docker-compose configuration sets MDCMS_STUDIO_ALLOWED_ORIGINS to the studio-example dev server origin. Add additional origins when embedding Studio in a separate application.