Skip to content

Permissions

oikapi uses role-based access control (RBAC) with three levels of granularity: application, table, and field — plus row-level security for filtering visible records.

Grant a role access to all tables in an application:

POST /api/apps/system/tables/permissions/records
{
"role_id": "<role-uuid>",
"resource_type": "application",
"resource_name": "crm",
"application": "crm",
"grants": {
"operations": ["read", "create", "update"]
}
}

When a new table is added to the CRM application, this role automatically gets access.

Override application permissions for a specific table:

POST /api/apps/system/tables/permissions/records
{
"role_id": "<role-uuid>",
"resource_type": "table",
"resource_name": "deals",
"application": "<app-name>",
"grants": {
"operations": ["read", "create", "update", "delete"]
}
}

Control which fields a role can read or write using columns.allow (whitelist) or columns.deny (blacklist):

POST /api/apps/system/tables/permissions/records
{
"role_id": "<role-uuid>",
"resource_type": "table",
"resource_name": "employees",
"application": "<app-name>",
"grants": {
"operations": ["read", "update"],
"columns": {
"allow": ["id", "name", "email", "department", "title"],
"deny": ["salary", "ssn"]
}
}
}

Use allow to whitelist specific fields, or deny to blacklist sensitive ones. Field-level restrictions only apply to table-level permissions.

When multiple permissions apply, the most specific one wins:

  1. Table-level grant (priority 500) — most specific
  2. Per-record grant (priority 300) — additive sharing of individual records
  3. Application-level grant (priority 100) — broad access
  4. No permission (priority 0) — implicit deny

Example: A role has read-only CRM access (application-level) but full access to “deals” (table-level). Result: read-only on all CRM tables except “deals”, which has full CRUD.

Grants can target a role, a team, or a dynamic group (a computed collection whose membership is materialized by graph traversal). All three resolve through the same grant path and priority ladder above — a user’s effective access is the union (most-permissive wins) of the grants on every role they hold, every team they belong to, and every dynamic group they are a member of.

Add filter expressions to permissions so users only see matching records:

POST /api/apps/system/tables/permissions/records
{
"role_id": "<role-uuid>",
"resource_type": "table",
"resource_name": "deals",
"application": "<app-name>",
"grants": {
"operations": ["read", "update"],
"row_filter": "eq(assigned_to, $user.id)"
}
}

RLS filter variables use a $ prefix (no braces):

VariableDescription
$user.idCurrent user’s UUID
$user.emailCurrent user’s email
$user.rolesComma-separated list of the user’s role names
$user.teamsComma-separated list of the user’s team names
$meAlias for $user.id

$user.role_ids and $user.team_ids (UUID forms) are also available.

For cross-table access control, use reference_access to grant access to records based on a foreign-key relationship to a table the user already has permission on. For example, grant access to tasks whose project_id points to a project the user can see:

{
"operations": ["read", "update"],
"reference_access": {
"source_table": "projects",
"via_fields": ["project_id"]
}
}

Set "reverse": true when the foreign key lives on the source table instead of this one. You can optionally narrow visible fields with allowed_columns or denied_columns.

OperationDescription
readList and retrieve records
createCreate new records
updateModify existing records
deleteDelete records

oikapi does not have an explicit deny mechanism. To restrict access:

  • Don’t grant the permission (implicit deny)
  • Override with a more restrictive table-level permission