Skip to content

Authentication

Every CM Box API request is authenticated with a JSON Web Token (JWT) sent as a bearer token. Machine-to-machine integrations obtain that token by authenticating a service account through the OAuth2 client credentials grant. This page explains the token flow, how requests carry the token, and how a service account’s permissions are determined.

Service account credentials
POST /oauth2/token (client_credentials grant)
JWT access token (valid 1 hour)
Authorization: Bearer <token> on every API request
Middleware verifies the JWT → route runs → permission checks apply

Authentication happens in middleware before your request reaches any route. The middleware reads the Authorization: Bearer header (or, for browser sessions, a token cookie), verifies the JWT’s signature and expiry, and attaches the authenticated identity to the request. Requests without a valid token never reach the API route. After authentication, each endpoint enforces its own required permissions — see the permissions reference.

A service account is a non-human identity for API clients. An administrator creates one in the security admin area or via POST /api/security/serviceAccounts. Two values matter to you as an integrator:

  • ID — the account’s identifier, used as the OAuth2 client_id.
  • Secret — used as the OAuth2 client_secret. The plaintext secret is returned only once, at creation time; CM Box stores only a hash of it, so a lost secret cannot be retrieved later.

Service accounts hold no permissions directly. They are assigned roles (directly or through group membership), and roles carry the actual grants — permission bundles, scoped permission lists, and overrides. See how permissions attach below.

Exchange the service account credentials for a token at POST /oauth2/token. The request body is form-encoded (application/x-www-form-urlencoded), and client_credentials is the only supported grant type:

Field Value
client_id Service account ID
client_secret Service account secret
grant_type client_credentials (only supported value)
Terminal window
curl -X POST https://cmbox.example.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=my-service-account" \
-d "client_secret=YOUR_SECRET" \
-d "grant_type=client_credentials"

A successful response returns the JWT and its lifetime in seconds:

{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 3600,
"token_type": "Bearer"
}

Error responses use a single error field:

Status error Cause
400 unsupported_grant_type, only client_credentials is supported grant_type was not client_credentials
401 invalid_client Unknown service account ID or wrong secret

Send the token in the Authorization header on every request:

Terminal window
curl https://cmbox.example.com/api/security/me/permissions \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

GET /api/security/me/permissions returns the calling identity’s effective permission set, which makes it a convenient first call to confirm both that your token works and what it is allowed to do.

Tokens expire one hour after issue (expires_in: 3600). The client credentials grant does not issue refresh tokens — when a token expires, request a new one from /oauth2/token. A long-running client should track the expiry and re-authenticate before it lapses; a 401 or a redirect on a previously working call typically means the token has expired.

How permissions attach to a service account

Section titled “How permissions attach to a service account”

A service account’s effective permissions are resolved the same way as a user’s:

  • The account is assigned roles, directly and through its groups.
  • Each role contributes permission bundles (named permission sets such as bundle.content_editor), explicit permission keys scoped globally, per repository, or per site, and grant/revoke overrides.
  • Bundle permissions apply globally — across all repositories and sites. To restrict a service account to one repository, use a role with repository-scoped permission keys instead of a bundle.

The full key catalog, the built-in bundles, and the resolution rules are in the permissions reference.

A small set of endpoints serves public content without a token when the repository is configured as public: published-asset and published-item endpoints, the GraphQL endpoint (which applies its own per-repository rules), and media embeds. Everything else requires a valid bearer token.

  • Permissions reference — permission keys, scopes, and bundles
  • Architecture overview — where authentication sits in the request flow
  • REST API reference — see the REST API Reference section in the sidebar for per-endpoint details, including /oauth2/token