Overview

CX-Engine uses OAuth 2.0 Bearer tokens. Tokens are scoped to either the central platform or a specific workspace. Use POST /api/switch-to to move between scopes without logging in again.


OAuth 2.0

CX-Engine supports two OAuth 2.0 grant types for delegated and machine-to-machine access:

Grant type Use case
Authorization Code Interactive, user-delegated access via browser redirect
Client Credentials Server-to-server access without user interaction

Before you begin: To use any OAuth 2.0 flow, you must first create an OAuth client in your CX-Engine dashboard. This gives you a client_id and client_secret required for all grant types.

Authorization Code Grant

Used when your application acts on behalf of a user. The user approves access in their browser and your application receives an authorization code to exchange for tokens.

Step 1 — Redirect the user

GET /oauth/authorize

Parameter Type Description
client_id string Your application's client ID
redirect_uri string URI to redirect to after authorization
response_type string Must be code
scope string Space-separated list of requested scopes (optional)
state string Random string for CSRF protection (recommended)

The redirect_uri must exactly match one of the redirect URIs registered on your OAuth client. Requests with an unregistered URI will be rejected.

The user is shown an approval screen. On approval they are redirected to your redirect_uri with a code query parameter.

Step 2 — Exchange the code for tokens

POST /oauth/token

Field Type Description
grant_type string authorization_code
client_id string Your client ID
client_secret string Your client secret
redirect_uri string Must match the URI used in Step 1
code string The authorization code received

Response 200

{
  "token_type": "Bearer",
  "expires_in": 31536000,
  "access_token": "eyJ0eXAiOiJKV1Q...",
  "refresh_token": "def50200..."
}

Client Credentials Grant

Used for server-to-server communication where no user interaction is involved.

POST /oauth/token

Field Type Description
grant_type string client_credentials
client_id string Your client ID
client_secret string Your client secret
scope string Space-separated list of requested scopes (optional)

Response 200

{
  "token_type": "Bearer",
  "expires_in": 31536000,
  "access_token": "eyJ0eXAiOiJKV1Q..."
}

Client credentials tokens do not include a refresh token.


Refresh a Token

POST /oauth/token

Field Type Description
grant_type string refresh_token
refresh_token string The refresh token from a previous token response
client_id string Your client ID
client_secret string Your client secret
scope string Must be equal to or a subset of the original scopes

Response 200

{
  "token_type": "Bearer",
  "expires_in": 31536000,
  "access_token": "eyJ0eXAiOiJKV1Q...",
  "refresh_token": "def50200..."
}

Refresh token rotation: Each call to this endpoint invalidates the previous refresh token and issues a new one. You must persist the refresh_token returned in every response — reusing an old refresh token will result in an error.


Revoke a Token

DELETE /oauth/tokens/{token_id}

Headers: Authorization: Bearer {access_token}

Response 204 — token revoked.


Central API

POST /api/login

Authenticates a user against the central platform and returns a central-scoped Bearer token.

Request body

Field Type Required Description
email string yes User email address
password string yes User password

Response 200

{
  "message": "success",
  "token": "eyJ0eXAiOiJKV1Q...",
  "user": { "id": 1, "name": "Jane Doe", "email": "jane@example.com" },
  "workspaces": [...],
  "pending_invites": [...]
}

Response 401

{ "response": "invalid username and/or password." }

POST /api/register

Creates a new user account and returns a central-scoped Bearer token.

Request body

Field Type Required Description
name string yes Full name
email string yes Email address
password string yes Password
phone string no Phone number
mobile_phone string no Mobile phone number

Response 200

{
  "message": "success",
  "token": "eyJ0eXAiOiJKV1Q...",
  "user": { ... },
  "workspaces": [],
  "pending_invites": []
}

Response 422 — email already in use

{ "message": "An user with this e-mail address already exists." }

POST /api/logout

Revokes all tokens for the authenticated user across the central platform and all workspaces.

Headers: Authorization: Bearer {central-token}

Response 200

{ "message": "success" }

GET /api/whoami

Returns the identity of the currently authenticated user along with their workspaces.

Headers: Authorization: Bearer {central-token}

Response 200

{
  "message": "success",
  "user": { "id": 1, "name": "Jane Doe", "email": "jane@example.com" },
  "workspaces": [...],
  "current_workspace": null
}

When called with a workspace-scoped token, current_workspace includes the workspace name, group, roles and permissions:

{
  "current_workspace": {
    "name": "Acme Corp",
    "group": "admin",
    "roles": ["manager"],
    "permissions": ["customer.view", "customer.create"]
  }
}

POST /api/switch-to

Issues a new token scoped to a different workspace, or back to central, without requiring re-authentication.

Headers: Authorization: Bearer {current-token}

Request body — switch to a workspace

Field Type Required Description
workspace_id string yes* Target workspace ID

Request body — switch back to central

Field Type Required Description
central boolean yes* Pass true to return to central scope

*One of workspace_id or central is required.

Response 200

{
  "message": "success",
  "user": { ... },
  "workspace": {
    "id": "acme",
    "name": "Acme Corp",
    "group": "admin",
    "roles": ["manager"],
    "permissions": ["customer.view", ...]
  },
  "domains": ["acme.cx-engine.app"],
  "token": "eyJ0eXAiOiJKV1Q..."
}

Response 403 — workspace not accessible

{ "message": "You do not have access to this workspace." }

Workspace API

POST /api/login (workspace)

Authenticates a user against a specific workspace and returns a workspace-scoped Bearer token. Send this request to the workspace subdomain.

Request body

Field Type Required
email string yes
password string yes

Response 200

{
  "message": "success",
  "token": "eyJ0eXAiOiJKV1Q...",
  "user": { ... }
}

POST /api/logout (workspace)

Revokes the current workspace token only.

Headers: Authorization: Bearer {workspace-token}

Response 200

{ "message": "success" }