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.
Official TypeScript API client
Open Mercato ships an official, fully typed SDK published as @open-mercato/client. It wraps the generated OpenAPI schema so every request/response is type-safe across Node.js, Next.js, and browser runtimes.
npm install @open-mercato/client
import { createOpenMercatoClient } from '@open-mercato/client'
const client = createOpenMercatoClient({
baseUrl: process.env.OPEN_MERCATO_API_BASE_URL ?? `${process.env.APP_URL}/api`,
accessToken: async () => process.env.API_KEY,
})
const { data, error } = await client.GET('/auth/users', {
params: { query: { page: 1, pageSize: 20 } },
})
if (error) throw new Error(error.message ?? 'Request failed')
console.log(data?.items)
baseUrlis optional. When omitted the client tries environment variables (OPEN_MERCATO_API_BASE_URL,NEXT_PUBLIC_API_BASE_URL,NEXT_PUBLIC_APP_URL,APP_URL) and finally falls back tohttp://localhost:3000/api.accessTokenaccepts either a raw API key (omk_xxx.yyy) or a JWT. The helper automatically prefixes values withApiKeyorBearer, so you never have to manage headers manually.- Need retries, tracing, or logging? Pass
middlewarewhen callingcreateOpenMercatoClientto registeropenapi-fetchmiddlewares.
See the companion example project at open-mercato/api-client-example for a complete Next.js walkthrough that demonstrates environment setup, token management, and CRUD flows using this SDK.
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.
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.