Grants & permissions
Manage fine-grained access control with Engine-backed allow and deny grants.
Overview
Grants control who can access what data in your workspace. Each grant maps one workspace principal (human, group, Agent, orEveryone) to a stable resource (Workspace, Namespace, Table, or View) with an effect (allow or deny). Allow grants also have a role (viewer, editor, or admin). The grant stores oneresourceId; Loam derives its kind and current Namespace ancestry from the catalog tree.
Access is fail-closed: if no grant matches a request, it is denied. Workspace owners receive an explicit Admin allow targeted by the Workspace public ID. Ownership, a JWT role label, an API-key secret, or an endpoint never bypasses the grant resolver.
Roles
Three roles, each inclusive of the one below:
| Role | Permissions |
|---|---|
viewer | SELECT queries and list or browse metadata on the granted resource. |
editor | Everything in viewer, plus row mutations and creating, updating, renaming, or deleting ordinary Tables and Views. Editors cannot change Namespace structure, manage connections, publish data, or manage grants. |
admin | Everything in editor. A human Admin can also manage Namespace structure, connections, publication, and grants on a node where Admin is effective and throughout that node's subtree. |
Allow and deny effects
An allow grant carries a role. A deny grant carries no role. For an authenticated caller, a deny addressed to the direct user or any of their current groups vetoes authenticated authority, even when another authenticated subject or a descendant node has an allow.
Everyone is evaluated as a separate lane for every caller. An Everyone deny vetoes that lane and a deeper Everyone allow cannot reopen it, but it does not cancel authenticated human or group grants. If no applicable authenticated deny exists, Loam selects the nearest matching allow for the direct human and each current group. It combines those results with any surviving Everyone allow using the most permissive role; Everyone is capped at viewer. If no applicable allow remains, access is denied.
Hierarchical narrowing
Grants inherit through the catalog's actual Workspace and Namespace ancestry, at any supported depth. A Workspace grant applies throughout the workspace, while a Namespace grant applies to all descendant Namespaces, Tables, and Views. For each subject, an allow on a nearer ancestor overrides its broader allows. Direct-principal and current-group denies veto authenticated authority regardless of distance; Everyone denies veto only the public lane regardless of distance.
After resolving the nearest allow independently for each subject, Loam combines those subject roles using the most permissive result.
GET /v1/workspaces/{workspacePublicId}/grants?resourceId={administeredRootId}
List grants on nodes that the requesting human currently administers. A Workspace Admin can list all grants in the workspace; a Namespace Admin sees only grants and protected subject metadata within the explicitly requested administered subtree. Use the canonical Workspace ID asresourceId to request the full workspace. Editors and machine credentials cannot list protected grant data.
/v1/workspaces/{workspacePublicId}/grants?resourceId={administeredRootId}[
{
"id": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43101",
"workspaceId": "rw-us-east1-ws-0195a3c47d3e7ab18c4f123456789abc",
"effect": "allow",
"subjectPrincipalId": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43104",
"resourceId": "rw-us-east1-node-0195a3c47d3e7ab18c4f123456789abd",
"role": "viewer",
"createdAt": "2026-03-15T10:30:00Z"
},
{
"id": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43105",
"workspaceId": "rw-us-east1-ws-0195a3c47d3e7ab18c4f123456789abc",
"effect": "allow",
"subjectPrincipalId": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43100",
"resourceId": "rw-us-east1-node-0195a3c47d3e7ab18c4f123456789abf",
"role": "viewer",
"createdAt": "2026-03-14T09:00:00Z"
}
]POST /v1/workspaces/{workspacePublicId}/grants
Create or replace the canonical grant for a subject and node. Only an authenticated human with effective Admin on the target node can do this. Namespace Admin authority therefore delegates within that subtree, but not to ancestors or siblings. Editors and delegated or machine Admins cannot manage grants. This endpoint manages human, group, Agent, and Everyone principals. API keys and MCP OAuth authorizations are authenticators and never own grants.
Request body
{
"effect": "allow",
"subjectPrincipalId": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43104",
"resourceId": "rw-us-east1-node-0195a3c47d3e7ab18c4f123456789abd",
"role": "viewer"
}| Field | Type | Required | Description |
|---|---|---|---|
effect | string | Yes | allow or deny. A deny is an absolute veto and must omit role. |
subjectPrincipalId | string | Yes | The canonical same-workspace UUID for one human, group, Agent, or the seeded Everyone principal. Principal kind is resolved by Loam and is never repeated in the grant. |
resourceId | string | Yes | The stable regional Workspace public ID or public node ID for the target Namespace, Table, or View. Do not send a resource kind, path, or ancestor list. |
role | string | For allow | viewer, editor, or admin. Omit for deny. |
Try it
/v1/workspaces/{workspacePublicId}/grants{
"effect": "allow",
"subjectPrincipalId": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43104",
"resourceId": "rw-us-east1-node-0195a3c47d3e7ab18c4f123456789abd",
"role": "viewer"
}{
"id": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43106",
"workspaceId": "rw-us-east1-ws-0195a3c47d3e7ab18c4f123456789abc",
"effect": "allow",
"subjectPrincipalId": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43104",
"resourceId": "rw-us-east1-node-0195a3c47d3e7ab18c4f123456789abd",
"role": "viewer",
"createdAt": "2026-03-16T12:00:00Z"
}DELETE /v1/workspaces/{workspacePublicId}/grants/{grantId}
Revoke a grant by its ID. Only an authenticated human with effective Admin on the grant's target node can do this. Queued durable work rechecks current grants before commit, so revocation can stop an in-flight mutation.
curl -X DELETE https://rw-us-east1.api.loamdata.com/v1/workspaces/rw-us-east1-ws-0195a3c47d3e7ab18c4f123456789abc/grants/018f5f65-4a8c-7c2e-a4d9-7c7bf7e43101 \
-H "Authorization: Bearer $JWT"Returns 204 No Content on success.
Examples
Grant a user read access to a Namespace subtree
curl -X POST https://rw-us-east1.api.loamdata.com/v1/workspaces/rw-us-east1-ws-0195a3c47d3e7ab18c4f123456789abc/grants \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"effect": "allow",
"subjectPrincipalId": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43104",
"resourceId": "rw-us-east1-node-0195a3c47d3e7ab18c4f123456789abd",
"role": "viewer"
}'Deny a user access to a table
curl -X POST https://rw-us-east1.api.loamdata.com/v1/workspaces/rw-us-east1-ws-0195a3c47d3e7ab18c4f123456789abc/grants \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"effect": "deny",
"subjectPrincipalId": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43104",
"resourceId": "rw-us-east1-node-0195a3c47d3e7ab18c4f123456789abe"
}'Publish a Namespace with an Everyone viewer grant
curl -X POST https://rw-us-east1.api.loamdata.com/v1/workspaces/rw-us-east1-ws-0195a3c47d3e7ab18c4f123456789abc/grants \
-H "Authorization: Bearer $JWT" \
-H "Content-Type: application/json" \
-d '{
"effect": "allow",
"subjectPrincipalId": "018f5f65-4a8c-7c2e-a4d9-7c7bf7e43100",
"resourceId": "rw-us-east1-node-0195a3c47d3e7ab18c4f123456789abd",
"role": "viewer"
}'Group grants
Group grants resolve against current regional membership. Removing a human or Agent from a group removes inherited access on the next request. Adding a group as an Agent-use grantee does not add the Agent to that permission group.
Authenticator ceilings
API keys and MCP OAuth authorizations authenticate exactly one human or Agent principal. They do not appear as grant subjects and cannot copy grants. Optional node ceilings use stable public node IDs rather than kinds, paths, names, or caller-supplied ancestry.
Every request intersects the authenticator's live state and optional ceiling with the bound principal's current grants, groups, capabilities, and entitlements. A human related to an Agent assumption or OAuth connection supplies eligibility and audit attribution only; their personal data authority is never added. Machine principals cannot manage grants even when their data role is Admin.
Error responses
| HTTP Status | Code | Description |
|---|---|---|
| 401 | INVALID_TOKEN | Missing, invalid, or expired JWT. |
| 403 | ACL_DENIED | Your token does not have admin access to manage grants. |
| 404 | NOT_FOUND | Grant not found (for DELETE). |
| 400 | INVALID_ARGUMENT | Invalid subject type, subject ID, node ID, role, or grant ID. |
Last updated 2026-08-23