Skip to content
  1. Extras
  2. mxHeadless
  3. Authentication

Authentication ​

mxHeadless determines who calls the API. What they can do is decided by authorization (scopes and MODX ACL).

Identity types ​

TypeWhenMechanism
AnonymousPublic readsNo headers
SessionManager UI or front end with MODX cookieSession cookie
API keyCI, builds, server-to-server callsAuthorization: Bearer mxh_... or X-API-Key
OAuth tokenShort-lived service accessAuthorization: Bearer mxt_...

Check order: OAuth token → API key → session → anonymous.

API keys (mxh_*) ​

Format: mxh_{lookupId}_{secret}. The secret is shown once. The database stores password_hash().

bash
curl -s https://example.com/api/v1/resources \
  -H 'Authorization: Bearer mxh_a1b2c3d4_xK9mN2pQ8rT5vW1yZ6'

Creation: API keys.

OAuth tokens (mxt_*) ​

Disabled by default (mxheadless_oauth_enabled). Issue via POST /api/v1/auth/token.

Format: mxt_{tokenId}_{secret}. TTL: mxheadless_oauth_token_ttl (3600 s).

Details: OAuth.

Session and CSRF ​

With a session cookie, the current MODX user is attached.

Any session request creates $_SESSION['mxheadless.csrf_token'] if missing and returns it in X-CSRF-Token. Send the same header on POST/PUT/PATCH/DELETE. This is not the MODX core CSRF token.

Setting: mxheadless_csrf_enabled (default true). Bearer keys do not need CSRF. With CORS, add X-CSRF-Token to mxheadless_cors_expose_headers so JavaScript can read it.

Scopes ​

Pattern {object}.{action}: resources.read, chunks.read, products.read, preview, *.

Missing scope → 403 scope_denied. Missing credentials on a protected route → 401 token_required.

Preview ​

?preview=true returns unpublished content with view_unpublished (session) or scope preview (key/token). Anonymous preview is blocked.

Pipeline ​