MDCMS supports three authentication methods: API keys for server-to-server access, session cookies for browser-based Studio usage, and a CLI device flow for command-line tools.
API Key Authentication
API keys are the recommended method for server-to-server integrations, CI/CD pipelines, and SDK usage. Pass the key in the Authorization header:
Authorization: Bearer mdcms_key_live_abc123def456
API keys are scoped to specific capabilities and can be restricted to particular project/environment pairs. See Key Concepts — API Keys for details on scopes and configuration.
Session Authentication
Session-based auth is used by the Studio and browser clients. It requires a CSRF token for all mutation requests.
Login
Authenticate with email and password. Returns a session and sets an HTTP-only
session cookie.
Example request:
curl -X POST "https://cms.example.com/api/v1/auth/login" \
-H "Content-Type: application/json" \
-H "X-MDCMS-Project: marketing-site" \
-H "X-MDCMS-Environment: production" \
-d '{
"email": "editor@example.com",
"password": "s3cureP@ssw0rd"
}'
Response:
{
"data": {
"session": {
"id": "sess_abc123def456",
"userId": "550e8400-e29b-41d4-a716-446655440000",
"email": "editor@example.com",
"issuedAt": "2026-01-15T09:00:00.000Z",
"expiresAt": "2026-01-16T09:00:00.000Z"
}
}
}
The response also sets an mdcms_session HTTP-only cookie and a mdcms_csrf cookie containing the CSRF token. Include the CSRF token in the X-MDCMS-CSRF-Token header for all subsequent mutation requests.
Logout
End the current session. Requires session cookie and CSRF token.
Example request:
curl -X POST "https://cms.example.com/api/v1/auth/logout" \
-H "X-MDCMS-Project: marketing-site" \
-H "X-MDCMS-Environment: production" \
-H "X-MDCMS-CSRF-Token: csrf_token_value" \
-b "mdcms_session=sess_abc123def456"
Response:
{
"data": {
"success": true
}
}
SSO Authentication
Initiate OIDC
/api/v1/auth/sso/{provider}
Initiate an OpenID Connect authentication flow with an external identity
provider.
The identity provider slug (e.g., google, github, okta).
Example request:
curl -X POST "https://cms.example.com/api/v1/auth/sso/google" \
-H "Content-Type: application/json" \
-H "X-MDCMS-Project: marketing-site" \
-H "X-MDCMS-Environment: production"
Response:
{
"data": {
"redirectUrl": "https://accounts.google.com/o/oauth2/v2/auth?client_id=...&redirect_uri=...&scope=openid+email+profile&state=..."
}
}
Redirect the user to the redirectUrl. After successful authentication, the provider redirects back to the MDCMS callback URL, which establishes a session.
SAML Assertion Consumer
SAML assertion consumer service endpoint. Receives and processes SAML
assertions from the identity provider after authentication.
This endpoint is called by the SAML identity provider, not by client applications directly. On successful assertion validation, a session is established and the user is redirected to the Studio.
Response: HTTP 302 redirect to the Studio dashboard with session cookies set.
/api/v1/auth/saml/metadata
Returns the SAML service provider metadata XML document. Use this URL when
configuring MDCMS as a service provider in your identity provider’s admin
console.
Example request:
curl "https://cms.example.com/api/v1/auth/saml/metadata" \
-H "X-MDCMS-Project: marketing-site" \
-H "X-MDCMS-Environment: production"
Response: XML document with Content-Type: application/xml.
<?xml version="1.0" encoding="UTF-8"?>
<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
entityID="https://cms.example.com/api/v1/auth/saml/metadata">
<SPSSODescriptor
AuthnRequestsSigned="true"
WantAssertionsSigned="true"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<AssertionConsumerService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="https://cms.example.com/api/v1/auth/saml/acs"
index="1" />
</SPSSODescriptor>
</EntityDescriptor>
CLI Device Flow
The CLI uses a device authorization flow to authenticate without exposing credentials on the command line. This flow is initiated by mdcms login.
Start Challenge
Begin a CLI device authorization flow. Returns a challenge ID and a URL for
the user to authorize in their browser.
Project slug to authorize against.
Environment to authorize against.
Example request:
curl -X POST "https://cms.example.com/api/v1/auth/cli/start" \
-H "Content-Type: application/json" \
-d '{
"project": "marketing-site",
"environment": "production"
}'
Response:
{
"data": {
"challengeId": "ch_abc123def456",
"authorizeUrl": "https://cms.example.com/auth/cli/authorize?challenge=ch_abc123def456",
"expiresAt": "2026-01-15T09:10:00.000Z"
}
}
The challenge expires after 10 minutes. If the user does not authorize within
that window, the CLI must restart the flow.
Authorize Challenge
/api/v1/auth/cli/authorize
Authorize a pending CLI device challenge. Called from the browser after the
user logs in and approves the CLI session.
Example request:
curl -X POST "https://cms.example.com/api/v1/auth/cli/authorize" \
-H "Content-Type: application/json" \
-H "X-MDCMS-CSRF-Token: csrf_token_value" \
-b "mdcms_session=sess_abc123def456" \
-d '{
"challengeId": "ch_abc123def456"
}'
Response:
{
"data": {
"success": true,
"code": "authz_code_xyz789"
}
}
Exchange Code
/api/v1/auth/cli/exchange
Exchange the authorization code for an API key. Called by the CLI after the
user authorizes the challenge.
Example request:
curl -X POST "https://cms.example.com/api/v1/auth/cli/exchange" \
-H "Content-Type: application/json" \
-d '{
"challengeId": "ch_abc123def456",
"code": "authz_code_xyz789"
}'
Response:
{
"data": {
"apiKey": "mdcms_key_cli_abc123def456ghi789",
"expiresAt": "2026-02-15T09:00:00.000Z"
}
}
The CLI stores this API key locally and uses it for subsequent requests.
Current Principal
Get Current User
Returns the current authenticated principal’s identity and capabilities within
the active project and environment.
Example request:
curl "https://cms.example.com/api/v1/me" \
-H "X-MDCMS-Project: marketing-site" \
-H "X-MDCMS-Environment: production" \
-H "Authorization: Bearer mdcms_key_live_abc123"
Response:
{
"data": {
"principalType": "apiKey",
"principalId": "key_550e8400-e29b-41d4-a716-446655440000",
"label": "Production Read-Only",
"capabilities": {
"schema": {
"read": true,
"write": false
},
"content": {
"read": true,
"readDraft": false,
"write": false,
"publish": false,
"delete": false
},
"users": {
"manage": false
},
"settings": {
"manage": false
}
}
}
}
For session-based authentication, the response includes the user’s email and role instead of a key label:
{
"data": {
"principalType": "user",
"principalId": "550e8400-e29b-41d4-a716-446655440000",
"email": "admin@example.com",
"role": "admin",
"capabilities": {
"schema": { "read": true, "write": true },
"content": {
"read": true,
"readDraft": true,
"write": true,
"publish": true,
"delete": true
},
"users": { "manage": true },
"settings": { "manage": true }
}
}
}
Environments
List Environments
Returns all environments configured for the current project.
Example request:
curl "https://cms.example.com/api/v1/environments" \
-H "X-MDCMS-Project: marketing-site" \
-H "X-MDCMS-Environment: production" \
-H "Authorization: Bearer mdcms_key_live_abc123"
Response:
{
"data": [
{
"name": "production",
"extends": null,
"isDefault": true,
"createdAt": "2026-01-01T00:00:00.000Z"
},
{
"name": "staging",
"extends": "production",
"isDefault": false,
"createdAt": "2026-01-01T00:00:00.000Z"
},
{
"name": "development",
"extends": "staging",
"isDefault": false,
"createdAt": "2026-01-05T00:00:00.000Z"
}
]
}
The X-MDCMS-Environment header is still required for this endpoint, even
though it returns all environments. The header is used for authentication
context.