Guides
Authorization
Model row access with ownership, roles, and deny rules instead of spreading checks through handlers and UI code.
Start with the simplest rule that matches your app:
- ownership for personal data
- roles for admin access
- denies for hard stops such as immutable records
entity Document {
title: string,
ownerId: __User.id,
@grant read, write where resource.ownerId == principal.id
@grant read to role(Admin)
@deny delete to *
}Recommended Practice
- keep policies on the entity that owns the data
- prefer declarative policy conditions over hand-written permission checks
- use
.fields()in queries to minimize what leaves the server
A Good Mental Model
Think about authorization in layers:
- who can invoke a workflow belongs at the exposed-function or route boundary
- which rows are visible or mutable belongs on the entity
- which fields should come back is often a combination of field-level grants and
.fields()
This split prevents a common failure mode in other stacks, where an endpoint is protected but still reads or returns more data than intended.
Ownership First, Then Roles
For most products, the cleanest path is:
- start with ownership-based rules
- add role-based rules only when the product model truly needs them
- use deny rules for invariants, not as your primary policy style
That keeps policies readable, especially when AI tools or multiple engineers are working in the same schema.
Why This Matters For The Rest Of The Platform
Kizaki uses the same authorization model across:
- normal reads
- updates and deletes
- includes
- browser live queries
- routes and API-key-backed access
That consistency is the real reason to invest in good policies early.