Authentication & RBAC
All examples assume the environment variables defined in REST API Overview:
export BASE_URL="http://localhost:3000/api"
export API_KEY="<paste your API key secret here>"
export USER_ID="<target user uuid>"
export ROLE_ID="<target role uuid>"
Mint an API key following the Managing API keys guide and replace the placeholders with real values before running any request.
Login
Endpoint: POST /login
Features: Public (no token required)
Body: Form data (multipart/form-data or application/x-www-form-urlencoded)
Fields:
email— required user email.password— required password.remember— optional flag (true,on, or1) to create a long-lived session.requireRole— optional comma-separated roles the user must hold.
curl -X POST "$BASE_URL/login" \
-H "Accept: application/json" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "email=admin@example.com" \
--data-urlencode "password=supersecret" \
--data-urlencode "remember=true"
Successful responses include a JWT (token) and set the auth_token cookie:
{
"ok": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"redirect": "/backend"
}
Store the token securely if you need to keep a browser session alive, but use API keys for server-to-server calls.
The login endpoint uses two-layer rate limiting: 20 attempts per 60s per IP (regardless of email) and 5 attempts per 60s per IP+email combination. After exceeding either limit, the endpoint returns 429 Too Many Requests with a Retry-After header. Successful login resets the per-account counter. The password reset endpoints (POST /reset and POST /reset/confirm) are also rate limited. See Rate Limiting for configuration details.
Users
List Users — GET /auth/users
Feature: auth.users.list
Query parameters:
page/pageSize— pagination (defaults1/50, max100).search— case-insensitive match on email.organizationId— filter to a particular organization UUID.roleIds— comma-separated role UUIDs.
curl -X GET "$BASE_URL/auth/users?page=1&pageSize=20&search=admin" \
-H "X-Api-Key: $API_KEY" \
-H "Accept: application/json"
Sample response (truncated):
{
"items": [
{
"id": "f5d0220f-59a8-4b8d-ae2c-84f960cc6e6c",
"email": "admin@example.com",
"organizationId": "37efc239-87ab-4eb8-97f3-1cbbd7b497d0",
"roles": ["owner"],
"customFields": {
"cf_department": "Sales"
}
}
],
"total": 1,
"page": 1,
"pageSize": 20,
"totalPages": 1
}
Create User — POST /auth/users
Feature: auth.users.create
Body: JSON
curl -X POST "$BASE_URL/auth/users" \
-H "X-Api-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"email\": \"new.user@example.com\",
\"password\": \"TempPass123!\",
\"organizationId\": \"$ORG_ID\",
\"roles\": [\"manager\"],
\"customFields\": {
\"department\": \"Operations\",
\"onboardingDate\": \"2024-06-01\"
}
}"
Response:
{ "id": "c634b52b-1d0e-4fbf-9a0c-7c3df6f947a2" }
Update User — PUT /auth/users
Feature: auth.users.edit
Body: JSON with at least id.
curl -X PUT "$BASE_URL/auth/users" \
-H "X-Api-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"id\": \"$USER_ID\",
\"email\": \"updated.user@example.com\",
\"organizationId\": \"$ORG_ID\",
\"roles\": [\"manager\", \"support\"],
\"customFields\": {
\"department\": \"Customer Success\"
}
}"
Response:
{ "ok": true }
Delete User — DELETE /auth/users?id=<uuid>
Feature: auth.users.delete
curl -X DELETE "$BASE_URL/auth/users?id=$USER_ID" \
-H "X-Api-Key: $API_KEY" \
-H "Accept: application/json"
Response:
{ "ok": true }
Fetch User ACL — GET /auth/users/acl?userId=<uuid>
Feature: auth.acl.manage
curl -X GET "$BASE_URL/auth/users/acl?userId=$USER_ID" \
-H "X-Api-Key: $API_KEY" \
-H "Accept: application/json"
Example response:
{
"hasCustomAcl": true,
"isSuperAdmin": false,
"features": ["dashboard.widgets.view", "entities.records.manage"],
"organizations": ["37efc239-87ab-4eb8-97f3-1cbbd7b497d0"]
}
Update User ACL — PUT /auth/users/acl
Feature: auth.acl.manage
curl -X PUT "$BASE_URL/auth/users/acl" \
-H "X-Api-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"userId\": \"$USER_ID\",
\"isSuperAdmin\": false,
\"features\": [\"entities.records.manage\", \"entities.definitions.manage\"],
\"organizations\": [\"$ORG_ID\"]
}"
Response:
{ "ok": true }
Roles
List Roles — GET /auth/roles
Feature: auth.roles.list
curl -X GET "$BASE_URL/auth/roles?page=1&pageSize=50&search=admin" \
-H "X-Api-Key: $API_KEY" \
-H "Accept: application/json"
Create Role — POST /auth/roles
Feature: auth.roles.manage
curl -X POST "$BASE_URL/auth/roles" \
-H "X-Api-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "support-specialist",
"tenantId": null
}'
Response:
{ "id": "1dc9bc3a-8f9b-4d3f-af5d-7dbb37a4ba5c" }
Update Role — PUT /auth/roles
Feature: auth.roles.manage
curl -X PUT "$BASE_URL/auth/roles" \
-H "X-Api-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"id\": \"$ROLE_ID\",
\"name\": \"support-advanced\",
\"tenantId\": null
}"
Delete Role — DELETE /auth/roles?id=<uuid>
Feature: auth.roles.manage
Deletion fails with 400 if users are still assigned.
curl -X DELETE "$BASE_URL/auth/roles?id=$ROLE_ID" \
-H "X-Api-Key: $API_KEY" \
-H "Accept: application/json"
Fetch Role Features — GET /auth/roles/acl?roleId=<uuid>
Feature: auth.roles.manage
curl -X GET "$BASE_URL/auth/roles/acl?roleId=$ROLE_ID" \
-H "X-Api-Key: $API_KEY" \
-H "Accept: application/json"
Sample response:
{
"features": [
"dashboard.widgets.view",
"dashboard.widgets.manage",
"entities.records.view"
]
}
Update Role Features — PUT /auth/roles/acl
Feature: auth.roles.manage
curl -X PUT "$BASE_URL/auth/roles/acl" \
-H "X-Api-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"roleId\": \"$ROLE_ID\",
\"features\": [
\"auth.users.list\",
\"auth.users.create\",
\"dashboard.widgets.view\"
]
}"
Response:
{ "ok": true }
Admin Navigation — GET /auth/admin/nav
Feature: Authenticated user (feature checks executed per route)
Returns the backend sidebar groups for the current user, factoring tenant/organization scope and RBAC decisions.
curl -X GET "$BASE_URL/auth/admin/nav" \
-H "X-Api-Key: $API_KEY" \
-H "Accept: application/json"
Simplified response:
{
"groups": [
{
"name": "Dashboard",
"items": [
{ "href": "/backend", "title": "Overview", "enabled": true }
]
}
]
}
Use this endpoint to drive custom admin shells or to debug visibility rules when developing new modules.