For the complete documentation index, see llms.txt. This page is also available as Markdown.

Authentication

The Xibo CMS API is protected by OAuth 2.0.

Every request must carry a valid access_token in an Authorization header:

HTTP Header
Authorization: Bearer <<access token>>

This page covers how to register an application, obtain a token, refresh it, and scope it.

Throughout this page, replace https://cms.example.org with the URL of your CMS. If your CMS is installed in a sub-directory, include it — for example https://example.org/xibo/api/authorize/access_token.

Quick start

If you're building a server-side integration and just want a token, this is the whole flow:

curl -X POST https://cms.example.org/api/authorize/access_token \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"

Response:

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

Use it:

curl https://cms.example.org/api/display \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9..."

The rest of this page explains where the credentials come from and what to do when the token expires.

Step 1: Register an Application

Before you can request a token, an Application must exist in the CMS.

  1. Sign in to the CMS and go to AdministrationApplications.

  2. Select Add Application and give it a name. This name is shown to users on the authorisation screen, so make it recognisable.

  3. Save, then edit the new Application to configure it.

The Application edit form controls everything about how your integration authenticates:

Setting
What it does

Client ID

Public identifier for your application. Safe to include in configuration files.

Client Secret

Password for your application. Treat it like a password — see Keeping credentials safe.

Confidential

Whether the application can keep a secret. Leave enabled for server-side integrations.

Authorisation Code / Client Credentials

Which grant types this application may use. Enable only what you need.

Redirect URIs

Required for the authorisation code grant. The CMS will only redirect to a URI listed here.

Scopes

Which parts of the API this application may reach. Defaults to all.

Step 2: Choose a grant type

Two grant types are supported. Pick based on whose data you're acting on.

Client Credentials
Authorisation Code

grant_type value

client_credentials

authorization_code

Acts as

The user who owns the Application

The user who signs in and approves

Use for

Server-to-server integrations, scheduled jobs, middleware

Applications used by multiple CMS users, or where you must not hold user credentials

User interaction

None

Sign-in and consent in a browser

Refresh tokens

Not issued

Issued

Needs a redirect URI

No

Yes

Step 3: Obtain an access token

All token requests are POST to /api/authorize/access_token, with parameters in a form-encoded request body (application/x-www-form-urlencoded). They are not query string parameters.

Client credentials grant

A single request. There is no user to redirect and no consent screen.

The token acts as the CMS user who owns the Application. It can do everything that user can do, and nothing they cannot — API permissions are still subject to normal CMS user permissions and features.

Authorisation code grant

Three steps: send the user to the CMS, receive a code, exchange the code for a token.

1. Redirect the user to the authorisation endpoint

Parameter
Required
Notes

client_id

Yes

From the Application page.

response_type

Yes

Always code.

redirect_uri

Yes

Must exactly match one of the URIs registered against the Application.

scope

No

Space-delimited. Omit to receive all scopes configured for the Application.

state

Strongly recommended

Random per-request value. Verify it on return to protect against CSRF.

The user signs in if they aren't already, then sees an authorisation screen naming your application. If they approve, the CMS redirects to your redirect_uri.

2. Receive the authorisation code

Check that state matches the value you sent before going any further. If the user declines, you receive an error parameter instead of code.

3. Exchange the code for a token

Authorisation codes are valid for 10 minutes and may be used once.

Response:

Store the refresh_token securely alongside the user's record.

Refreshing a token

Access tokens last one hour. Rather than sending the user through the authorisation screen again, exchange the refresh token:

The response contains a new access token and a new refresh token. Replace the stored refresh token each time — the previous one is invalidated.

Client credentials integrations do not receive refresh tokens. Simply request a new token when the old one expires.

Step 4: Call the API

The API is served from /api on your CMS. Send the token as a Bearer credential on every request:

See OpenAPI for the full route reference, or Getting Started with Postman to explore interactively.

Token lifetimes

Token
Lifetime
Renewal

Access token

1 hour

Request a new one, or use a refresh token

Authorisation code

10 minutes, single use

Restart the authorisation flow

Refresh token

1 month

Rotated on every use

Cache your access token for its lifetime rather than requesting a new one per API call. Requesting a token on every call is wasteful and will trip rate limiting on busy systems.

Treat expires_in as advisory rather than a guarantee. Tokens can be invalidated early — for example if the Application's secret is reset or its scopes are changed. Handle a 401 at any time by re-authenticating and retrying once.

Scopes

Scopes limit which API routes a token can reach. Each scope defines a set of route and method combinations; a request is allowed if any scope on the token permits that route and method.

  • The all scope grants access to every route and is the default.

  • Request specific scopes with a space-delimited scope parameter on the token request.

  • If you request no scopes, the token receives every scope configured against the Application.

  • A token that reaches a route none of its scopes permit receives 403 Access to this route is denied for this scope.

Scopes are configured per Application under AdministrationApplications. Grant the narrowest set your integration needs — a data-feed integration that only writes to a DataSet has no reason to be able to delete Displays.

Scopes constrain a token; they do not expand it. The effective permission is the intersection of the token's scopes and the CMS permissions of the user the token acts as.

Error responses

Token endpoint errors follow the OAuth 2.0 error format:

400

unsupported_grant_type

grant_type missing, misspelled, or sent as a query parameter instead of a form field

400

invalid_request

A required parameter is missing

400

invalid_grant

Authorisation code expired, already used, or redirect_uri doesn't match the one used to obtain it

400

invalid_scope

A requested scope isn't configured against the Application

401

invalid_client

Wrong client_id/client_secret, or the grant type isn't enabled for this Application

401

access_denied

Access token expired or malformed

403

Token is valid but its scopes don't permit this route

Keeping credentials safe

  • Always use HTTPS. A Bearer token in a request over plain HTTP is a credential in the clear. The CMS should not be exposed over HTTP in production.

  • Never embed a client secret in a browser or mobile application. Anything shipped to a device is public. Client credentials belong on a server you control.

  • A client credentials token inherits the Application owner's permissions. Create a dedicated CMS user for each integration, with only the permissions and features that integration needs, and own the Application from that user. Don't run integrations as a Super Admin out of convenience.

  • Store secrets outside your codebase — environment variables or a secrets manager, never source control.

  • Reset the secret if it may have leaked. Resetting takes effect immediately.

  • Review Applications periodically and delete ones no longer in use.

Troubleshooting

I get unsupported_grant_type even though I sent a grant type

The parameters must be in the POST body as application/x-www-form-urlencoded, not in the query string and not as JSON. In cURL, use -d; in most HTTP libraries, this is the "form" or "form_params" option rather than the "json" option.

Also check the value itself: the authorisation code grant is authorization_code, not access_code or auth_code.

I get invalid_client with credentials I'm sure are correct

Check that the grant type you're requesting is enabled against that Application. An Application with only Client Credentials enabled will reject an authorization_code request with invalid_client rather than a more specific error.

Also confirm you're using the Client ID and Secret, not a CMS username and password.

The authorisation redirect fails or returns to the wrong place

The redirect_uri must match a URI registered against the Application exactly, including scheme, host, port, path, and trailing slash. The same value must then be sent again when exchanging the code.

Everything worked, then started returning 401 after an hour

Working as intended — access tokens last one hour. Cache the token with its expiry and renew before or on expiry, rather than assuming a token is permanent.

API configuration problem, consult your administrator

The CMS could not load its API signing keys. On a self-hosted install, check that the private key path and encryption key are configured and readable by the web server. Contact your CMS administrator, or Xibo Support if you are Cloud hosted.

Last updated

Was this helpful?