All chapters
Data
Permission rules for an internal tool - scava.json
To control who may see and change what in an internal tool, put a file named scava.json next to index.html. It says, per collection of entries, who reads and who writes. Scava enforces these rules on its own server for every request, so they hold even if someone edits the page in the browser or sends requests by hand. The app only shows or hides buttons; it is never the place where permissions are decided.
The file #
{
"name": "Team vacation",
"data": {
"vacation": { "read": "all", "write": "own" }
},
"files": {
"receipts": { "read": "own", "write": "own" }
}
}
nameis the display name of the app.dataholds the rules for database collections,filesthe rules for file collections. Use the collection name as the key. A collection name of"*"is the rule for every collection that has none of its own.- A collection without a rule, and no
"*", gets the default: read: all, write: own. - Server code has its own settings in the same file:
serverwithschedulesandwebhooks. See Schedules and webhooks.
The four values #
| Value | For read | For write |
|---|---|---|
"all" | Everyone who can open the app reads all entries. | Everyone changes and deletes all entries and adds new ones. |
"own" | Each person reads only the entries they created. | Each person adds entries and changes or deletes only the entries they created. |
"owner" | Only the creator of the app reads. | Only the creator adds, changes and deletes. |
"group:<name>" | Only members of that group read. | Members of that group add, change and delete every entry. |
"Own" means the entry's created_by is the person's email address.
The creator of the app can always read and change everything. A co-editor gets no more than the rules give any other person; they can, however, publish new rules.
Lists: any one is enough #
A list means a person needs only one of the values.
"read": ["own", "group:hr"]
Each person sees their own entries, and members of hr see all of them. Keep lists short; a list with too many values is refused.
Groups #
group:<name> refers to a group in the account of the app's owner, for example group:leads. The owner creates groups on the Overview page at scava.ai, in the browser. Agents cannot create groups. Group membership is read fresh on every request, so removing someone from a group takes effect at once.
If a version names a group that does not exist yet, publishing works and tells the agent which group is missing. Until the owner creates it, only the owner can do what the rule allows the group.
Rules for single fields #
Inside a collection, fields sets rules for single fields of an entry. They use the same values.
"vacation": {
"read": "all",
"write": ["own", "group:leads"],
"fields": {
"status": { "write": "group:leads" }
}
}
Field rules can only take away. They never give more than the rule of the collection.
- A field someone may not read is left out of every entry they receive: in lists, single entries and the answers to add and update.
- A field someone may not write cannot be set, changed or removed by them. Sending the field back unchanged is fine, so people can keep editing the rest of their entry.
ownfor a field means "only on entries the person created".- Field names use letters, digits,
-and_. Names like__proto__are not allowed. - Files have no field rules.
Example 1: a vacation planner where team leads approve #
{
"name": "Team vacation",
"data": {
"vacation": {
"read": "all",
"write": ["own", "group:leads"],
"fields": { "status": { "write": "group:leads" } }
}
}
}
What this does:
- Everyone sees all vacation entries, including the
status. - Everyone adds an entry for themselves and edits or deletes their own. They can write
from,toand a note, but they cannot setstatus. - Members of
leadscan change any entry, and only they can setstatus. In the app they click "Approve", which updates{ status: "approved" }. - Everyone else who tries to set
status, by hand or with a changed page, gets "Only members of leads and the owner of this app can set "status"."
The app can hide the "Approve" button for everyone who is not a lead, with scava.me() returning groups. The button is only a convenience. The rule is the lock.
Example 2: salaries that only the person and HR see #
{
"name": "Staff directory",
"data": {
"staff": {
"read": "all",
"write": ["own", "group:hr"],
"fields": {
"salary": { "read": ["own", "group:hr"], "write": "group:hr" }
}
}
}
}
Each employee creates one entry about themselves, with name, team and phone. HR adds the salary to any entry.
- Everyone reads the directory. The
salaryfield is missing from every entry except the person's own entry, and for members ofhr, who see it everywhere. - Employees edit their own entry (phone, team) but cannot set or change
salary, even on their own entry. - HR changes any entry and is the only group that writes
salary.
Because "own" means "created by this person", the employee must be the one who creates their own entry. If HR created the entries, nobody but HR would see the salaries.
Rules for files #
files uses the same values, with these differences: it has no fields, and the rule says who sees the list and downloads and who uploads. See Files.
Rules apply to server code too #
Server code acts with the rights of the owner by default. Use env.SCAVA.db('vacation', { as: 'me' }) to act with exactly the rights of the person who asks. Then the rules above apply to that person, groups and fields included. Without a person (a webhook or a schedule), as: 'me' is refused.
Checks at publish time #
Scava refuses a scava.json that is not valid JSON, has an unknown rule value, a bad collection name or bad field rules, and says what is wrong. The error text of a refused request tells the person who may do it, for example "Only members of hr and the owner of this app can add entries here."