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.
Permission levels
Section titled “Permission levels”Application-level
Section titled “Application-level”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.
Table-level
Section titled “Table-level”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"] }}Field-level
Section titled “Field-level”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.
Priority resolution
Section titled “Priority resolution”When multiple permissions apply, the most specific one wins:
- Table-level grant (priority 500) — most specific
- Per-record grant (priority 300) — additive sharing of individual records
- Application-level grant (priority 100) — broad access
- 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.
Row-level security (RLS)
Section titled “Row-level security (RLS)”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):
| Variable | Description |
|---|---|
$user.id | Current user’s UUID |
$user.email | Current user’s email |
$user.roles | Comma-separated list of the user’s role names |
$user.teams | Comma-separated list of the user’s team names |
$me | Alias for $user.id |
$user.role_ids and $user.team_ids (UUID forms) are also available.
Reference-based access
Section titled “Reference-based access”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.
Operations
Section titled “Operations”| Operation | Description |
|---|---|
read | List and retrieve records |
create | Create new records |
update | Modify existing records |
delete | Delete records |
No explicit deny
Section titled “No explicit deny”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