Access Control
Access rules are defined directly in each collection config file using helper functions. Rules are pure functions evaluated before every API operation. Any operation without a rule is allowed by default — except on auth collections, which are default-deny.
import { defineCollection, fields, hasRole } from "@/cms/core";
export default defineCollection({ slug: "posts", access: { create: hasRole("admin", "editor"), update: hasRole("admin", "editor"), delete: hasRole("admin"), publish: hasRole("admin", "editor"), }, fields: { ... },});In this example, read is not set so anyone can read posts. Only the operations you want to restrict need a rule.
Auth Collections
Section titled “Auth Collections”A collection with auth: true holds the passwords and roles that every other rule is checked against, so default-allow would let any signed-in account promote itself to admin or overwrite someone else’s password. These collections are therefore default-deny:
| Operation | Without an explicit rule |
|---|---|
create, delete |
Admins only |
read, update |
Admins, or your own record |
publish, schedule |
Admins only |
Two fields are protected regardless of the collection rule, so loosening access.update can’t accidentally re-open privilege escalation:
role— only an admin can set it, including on their own record.password— an admin, or the owner of that record. This is what lets a non-admin change their own password. Create and update differ: on create, onlyroleis stripped for non-admins (so a new account may set its initial password); on update, bothroleandpasswordare stripped for non-admins, unless a field-levelaccess.updaterule overrides.
Declaring your own rule replaces the default for that operation, and a field-level access.update rule on role or password replaces the field protection. Server-side code can still bypass everything with { _system: true }.
auth: true collections are part of Kide’s authentication boundary, not ordinary content. Do not pass untrusted input through _system, remove password hashing, or expose credential fields through custom serializers. See Authentication for the supported feature scope and evolution policy.
Helper Functions
Section titled “Helper Functions”| Helper | Description |
|---|---|
hasRole("admin") |
Checks if user has the specified role |
hasRole("admin", "editor") |
Accepts multiple roles (OR logic) |
access.tsstill exists but is auto-built from collection configs. You should not edit it directly.
Operations
Section titled “Operations”| Operation | When checked |
|---|---|
read |
find, findOne, findById, count |
create |
create |
update |
update |
delete |
delete |
publish |
publish, unpublish |
schedule |
schedule (falls back to publish rule) |
Context
Section titled “Context”({ user, doc, operation, collection }) => boolean;user- current session user ({ id, role, email, ...customUserFields }ornull)doc- existing document. Forfindandcount,readrules are evaluated per document so rules can hide individual rows.operation- operation namecollection- collection slug
Field-Level Access
Section titled “Field-Level Access”Individual fields support read and update access rules:
summary: fields.text({ access: { read: hasRole("admin"), // hidden from non-admins update: hasRole("admin"), // read-only for non-admins },}),readhides the field entirely from the admin UIupdatemakes the field read-only in the admin UI; values are silently preserved on save