Skip to content

Access rules

Included free on every install, with rules for up to three roles. More roles need a license with the rbac-pro feature. See pricing.

An access rule says what one role may do with one resource. It names the role, the resource, the actions allowed, and the fields removed from what that role reads. Rules apply to people who sign in, in the admin console or with a session token.

A rule is four fields:

{
"role": "editor",
"schema_name": "articles",
"actions": ["read", "update"],
"field_mask": ["internal_notes"]
}
FieldMeaning
roleThe role the rule applies to. Required.
schema_nameThe resource. Required.
actionsWhat the role may do: create, read, update, delete, and activate on flows and reviews.
field_maskFields removed from what this role reads.

The resource is one of:

ResourceWritten as
One content typeIts name, such as articles
Every content type*
Flowsflows for every flow in the tenant, or flow:<slug> for one
Reviewsreviews for every review definition, or review:<slug> for one

activate publishes, disables, rolls back, runs, tests and invokes a flow, and moves an entry through a review. On a content type it is refused with 422.

  • Specific beats general. A rule for articles replaces the * rule for that content type. A rule for flow:<slug> replaces the flows rule for that flow. The * rule never applies to flows or reviews.
  • An empty action list denies. A rule for articles with no actions blocks that role on articles, even when the * rule allows it everywhere else.
  • Field masks add up. When a specific and a general rule both apply, both masks apply. A user holding two roles has every field hidden that either role hides.

Three answers are fixed:

  • A super admin is allowed everything and reads every field.
  • An admin is allowed every flow and review until a rule names admin on that resource. From then on the rule decides.
  • Any other role with no rule is refused.

A fresh install has no rules, so only super admins read or write content until you write some.

This gives a reader role the titles of the post content type from the quickstart, with the body hidden. You need a super admin token in TOKEN. The quickstart shows how to get one.

  1. Check how many roles may still hold rules:

    Terminal window
    curl http://localhost:3001/api/admin/permissions/limits \
    -H "Authorization: Bearer $TOKEN"
    { "roles": { "limit": 3, "current": 0 } }

    A limit of 0 means no ceiling.

  2. Create an account that holds only the reader role:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/users \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"email": "reader@example.com", "password": "Reader-Account-2026", "roles": ["reader"]}'

    The answer is 201 with the new user.

  3. Sign in as that account and keep its token:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/auth/login \
    -H "Content-Type: application/json" \
    -d '{"email": "reader@example.com", "password": "Reader-Account-2026"}'

    Copy token into READER_TOKEN. Reading posts now answers 403 with permission denied, because no rule names reader.

  4. Write the rule:

    Terminal window
    curl -X POST http://localhost:3001/api/admin/permissions \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"role": "reader", "schema_name": "post", "actions": ["read"], "field_mask": ["body"]}'
    {
    "id": "72a42ef6-948b-445b-80df-b315e1480f8f",
    "role": "reader",
    "schema_name": "post",
    "actions": ["read"],
    "field_mask": ["body"],
    "created_at": "2026-10-01T09:30:00Z",
    "tenant_id": ""
    }

    The answer is 200. Sending a rule for the same role and resource again replaces it.

  5. Read as the reader:

    Terminal window
    curl http://localhost:3002/api/v1/content/post \
    -H "Authorization: Bearer $READER_TOKEN"

    Every entry comes back with title and without body.

  6. Open Access > Permissions in the admin console. The reader rule is in the list. Only a super admin sees the page.

Write a rule for that content type with no actions. It overrides any * rule for the same role:

{ "role": "editor", "schema_name": "payroll", "actions": [] }

To open it again, delete the rule or send it again with the actions you want.

A rule on a flow or review belongs to the tenant it was written in. A content type rule and the * rule apply in every tenant. A tenant's own rule on a resource takes the place of the shared one.

Renaming a flow keeps its access. Deleting a flow deletes its rules, so a new flow with the same slug starts with none. Deleting a tenant deletes the rules it wrote.

A change applies at once on the replica that saved it. Other replicas apply it when they are told of the change, or at the latest after CACHE_TTL. See scaling for running more than one replica.

VariableWhat it doesDefault
CACHE_TTLHow long a replica keeps rules it has read. 0s reads them on every request.60s

Access rules run on every install. If you set LYEVE_PLUGINS, include permissions in it. See licensing and tiers.

Without rbac-pro, the rules a tenant sees may name three different roles, and a license without rbac-pro does not raise that number. A rule for a fourth role answers 402:

{ "error": "cap_exceeded", "cap": "rbac.roles", "limit": 3, "current": 3, "upgrade_url": "" }

Editing a rule for a role that already has one is always allowed, because it adds no role. An install already past the ceiling keeps every role it has.

Every route needs a super admin with a signed-in session. An admin token is refused with 403 This route needs a signed-in session.

Rule routes
MethodPathResult
GET/api/admin/permissionsEvery rule your tenant sees. [] when there are none.
POST/api/admin/permissionsCreates the rule for that role and resource, or replaces it. 200.
DELETE/api/admin/permissions/{id}204, or 404 permission not found.
GET/api/admin/permissions/limitsThe role ceiling and how many roles hold rules.
StatusMessageCause
403permission deniedA content request from a role no rule allows.
402cap_exceededA new role would pass the role ceiling.
422invalid action: <action>The action is unknown, or activate on a content type.
Every error the rule routes return
StatusMessageCause
400invalid request bodyThe body is not JSON.
400invalid idThe id in the path is not a UUID.
402cap_exceededA new role would pass the role ceiling.
403This route needs a signed-in session.An admin token called a rule route.
404permission not foundNo rule has that id in your tenant.
422role and schema_name are requiredA required field is empty.
422invalid resource: a schema name, *, flows, flow:<slug>, reviews or review:<slug>The resource is not one a rule can name.
422invalid action: <action>The action is unknown, or activate on a content type.