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_idandclient_secretrequired 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_urimust 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_tokenreturned 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" }