Roles and RBAC
What a role really is — from Sam deciding what a volunteer may do, down to everything one permission rule can say.
#Roles
When Sam set up Emu Watch, the first real decision was not about any sighting. It was: what is a volunteer? Someone who may log sightings and edit their own. What is a ranger? Someone who may also mark a sighting verified. Those decisions are roles, and everything else in the permission system stands on them.
Sharing, flocks and ownership all decide which sightings a person reaches; the role decides what they are allowed to do at all. Get the role wrong and nothing else will save you; get it right and nothing else can undo it.
Flocks are crews in the API, and your Nest — the site you sign in to — is a
project there.
This way of organising access — a named role holding a list of permissions, assigned to people — is what the industry calls role-based access control, or RBAC. That is the only jargon on this page. The rest goes from the everyday idea down to the detail, so stop reading wherever it stops being useful.
#Level 1 — a role is a job title
Every person has a role. It is the answer to "what is this person here to do?"
| Role | On Emu Watch |
|---|---|
super_admin |
Owns the place. Sees everything, bypasses every row rule. |
admin |
Sam — runs the place: collections, users, roles, access. |
editor |
Makes and changes content where allowed. |
viewer |
Reads content where allowed. |
api |
Not a person: an API key's identity, scoped by the key's role. |
public |
Anyone not signed in — a visitor browsing the public map. |
You can add your own. Emu Watch adds two:
volunteer— Priya and Ben. May create sightings and edit their own; may not touch thestatusfield.ranger— the Rangers flock holds this. May setstatus, which is the whole difference between them and a volunteer.
A person can also end up with more than one role — a flock can hand a member an extra one from a menu Sam wrote (see roles inside a flock below). Where that happens the roles add together: each contributes the permissions it carries.
super_adminis a flag, not a name. Renaming a role cannot make it super-admin, and renaming super-admin cannot take the power away. This matters because "the role called admin" is a much weaker guarantee than "the role marked as administrator", and one of those can be changed by anybody who can rename roles.
#Level 2 — a role is a list of permissions
A role on its own means nothing. What gives it meaning is a list of rules, each one saying:
on this RESOURCE, you may perform this ACTION
A resource is a thing: a collection (collections/sightings), or a system
area (system/users, system/crews, system/files). An action is a verb:
create, read, update, delete, transfer or manage.
So Emu Watch's volunteer role holds:
collections/sightings read
collections/sightings create
collections/sightings update
system/files read
Two things follow, and both trip people up:
Nothing is allowed by default. If a role has no rule for a resource, it cannot touch it. There is no "everything except" — you list what is allowed.
transfer is its own verb, on collections only. It hands a record to a new
owner, and it is deliberately not part of update — update is the permission
most freely given, and folding a handover into it would let every editor
reassign anybody's records. manage includes it; nothing else does. See
Ownership.
manage is not "a bit more than update". It is the administrative verb, for
things like configuring a flock's role catalogue or writing
never-rules. Handing out manage on a system
resource is a much bigger decision than handing out update.
Edit these under Auth → Roles, or through GET/PUT /api/v1/roles/:id/permissions.
#Level 3 — a permission rule can say more than resource and action
A rule is not just resource + action. Each one can carry four further qualifications, and this is where most of the real power lives.
#Which rows — item_filter
Limits the rule to records matching a condition. Leave it empty and the rule covers everything.
{ "created_by": { "_eq": "$CURRENT_USER" } }
That is "only the ones they ADDED". The $CURRENT_USER part is filled in per
request, so one rule serves everybody.
Not quite the same as "only their own". Since records can be handed over, the Access screen's Reaches → Only their own writes a slightly bigger rule: transferred to me, or made by me and never transferred. A sighting Priya gave to Ana is Ana's under that rule and neither person's under the one above. Write
created_byby hand only when you really mean who ADDED the record — see Ownership.
Other variables you can use: $CURRENT_ROLE, $PROJECT_ID, $NOW,
$NOW_DATE. (The three crew variables were removed with crew scoping — a rule
still naming one is refused. Reach a flock with a
share instead.)
This is the single most important field on the page. Dropping it does not produce an error — it produces a rule that quietly reaches every row.
This is also how Emu Watch's public map works: the public role's read rule on
collections/sightings carries { "status": { "_eq": "verified" } }. One
standing rule, and every verified sighting is visible to visitors — the
collection rule
from the overview, seen from underneath.
#Which columns — fields
A security allow-list. Columns not on it never leave the server, for anybody holding this rule. Use it for the sighting's exact coordinates, the internal note, the email address.
#Which columns to SHOW — ui_fields
Presentation only. The value is still returned by the API — an export or an integration needs it — but the dashboard does not put it in front of this role.
If you want a column kept secret, use
fields.ui_fieldsonly tidies the screen. Reaching for the wrong one of these is an easy and expensive mistake.
#Always set — presets
Values forced on creation, whatever the caller sent.
{ "status": "unverified" }
Every sighting Priya logs starts unverified, whether or not she asked.
#Must be true — validation
A condition every write must satisfy, checked against what the record will look like afterwards — not against what was sent. That distinction is what stops a value being sneaked past by omitting it.
{ "status": { "_eq": "unverified" } }
#The two together
presets and validation as a pair are exactly how Emu Watch splits volunteers
from rangers:
Volunteers may log sightings, but only a ranger may verify one.
The volunteer role gets presets: {"status": "unverified"} and
validation: {"status": {"_eq": "unverified"}}. Priya can create and edit
freely; any attempt to move the status fails. The ranger role gets neither, so
it can.
Edit all of them in the permission matrix: click a granted cell to open its rules.
#Which columns they may CHANGE — write_fields
fields above gates what a role may SEE. It does not gate what a role may SET,
and for a long time nothing did — a role limited to species, notes could still
write status.
write_fields is the write-side list. Leave it empty and the role may set any
column it can otherwise write.
#Which columns freeze after create — immutable_fields
Settable once, when the record is made, and never again. Useful for the fields that decide where a record belongs, which should not move under it later.
Two lists, two jobs.
fieldsis about reading;write_fieldsis about writing. Somebody who could read a column they cannot change is ordinary, and so is the reverse — so neither list implies the other, and setting one does nothing to the other.
#Who wrote the rule — source
Not something you set: the gateway stamps it. A cell holds one row per writer —
the role editor (manual), the collection's Access tab (access_config), a
collection preset, a visibility rule — so the Access tab rewriting its own rules
no longer destroys a filter you wrote by hand. The access inspector reports the
result as "Composed from: …".
#Level 4 — how a request is actually decided
The one sentence from the overview, as the engine runs it:
Can this person do this action to this record?
1. Does a role they hold allow the ACTION
on this resource? ─── no ──> refused
│ yes
2. Is the record within REACH — theirs, or
shared with them (directly or through a
flock, capped by their place in it), or
covered by a collection rule? ─── no ──> refused
│ yes
3. Does a NEVER-RULE match the record? ─── yes ──> refused
│ no
allowed
Step 1 is the ceiling: no share, flock or rule can add an action a role does not allow. Step 2 is the reach, and any one door is enough. Step 3 is terminal — it is the only step that can say no to an owner, and by default it says no to administrators too.
#Roles inside a flock
A flock has its own three-rung ladder — viewer, editor, admin — that governs how far into that flock's content you go. Ben is a viewer in the Coastal Volunteers; Ana is an editor there. Neither of those is a Nest role, and neither gives them anything outside the flock.
Separately, a flock can hand a member a real Nest role from a catalogue:
species_editor, ranger, whatever an administrator has published to that
flock. This is how Sam's rangers get their power — the Rangers' catalogue
carries the ranger role, and the flock hands it to its members.
The split is what makes it safe to let anybody create a flock:
A flock admin chooses who gets a role. A Nest administrator chooses which roles exist to give.
If those were the same person, Priya could put an admin role on the Coastal
Volunteers' own menu and then take it. So the catalogue is edited only by
someone holding system/crews manage, and a role marked as administrator
can never be put on one at all.
To publish a role to flocks: turn on Flock-assignable for it under Auth → Roles, then add it to a flock's catalogue on that flock's page.
#API keys
A key carries a role, and can be narrowed further by per-key scopes. The result is the intersection: a key can never do more than its role, and within that, only what its scopes allow.
#Checking your work
System → Access answers the questions you actually have:
- Why can this person do that? — traces the decision gate by gate
- Who can do this? — every principal that reaches a given action
- What is exposed? — every collection, and how open it is
- What looks wrong? — lints the configuration for common mistakes
It reports roles, flocks, API keys, file containers and live share counts, so between them they account for everything a person can reach.
#Next
- Flocks and sharing — the two ways to reach a group
- Sharing an item — levels, expiry, revoking
- Never-rules — the rule that beats every role on this page
- Recipes — Emu Watch's setups, ready to copy
- Access control reference — the full technical detail