Grants
A role says which verbs; a grant says which tables — and a user's grants, if they have any, are the whole story.
One sentence carries this whole page:
A user's grants, if they have any, are the whole story, and a user with none is governed by their role.
That is what lets grants exist without changing what any already-declared user may do, and it is what makes them capable of narrowing — a permission system that can only widen is decoration.
DEFINE NAMESPACE prod;
USE NAMESPACE prod;
DEFINE DATABASE shop;
USE DATABASE shop;
DEFINE COLLECTION users;
DEFINE COLLECTION orders;
An editor with no grants may write every table in their database. Give that
same editor one grant and they reach exactly one table:
GRANT read, write ON orders TO ada;
They can no longer read users at all. Nothing about their role changed; the
grant became the whole answer.
The two verbs
| verb | covers |
|---|---|
read | reading records |
write | writing records, and declaring structure on the table |
A verb the language does not have is refused where it is written:
GRANT scribble ON users TO nobody;
NoSuchVerb. And so is a revocation of one:
REVOKE scribble ON users FROM nobody;
A grant names a user and a table, and both have to exist:
GRANT read ON users TO nobody;
Unknown — there is no such user.
GRANT read ON nonesuch TO nobody;
Unknown — nor such a table.
Fields
A grant may narrow to named fields as well:
GRANT read ON users FIELDS name, email TO ada;
The same rule applies one level down: what is named is the whole story, and
naming nothing names no limit. A grant with no FIELDS reaches every field.
FIELDS goes with read and not with write, and the refusal is deliberate: a
whole-record write by somebody who can only see three of a record's eight fields
would erase the five they cannot see, which is not a permission anybody means to
give.
Revoking will not remove the last one
This is the rule that surprises people, and it is the right surprise. Going from
one grant to none does not lock a user out — it widens them, from a named
table back to every table their role allows. That is the opposite of what
somebody typing REVOKE is thinking about.
So the last one is refused, with LastGrant, and the refusal says how to widen
on purpose. Removing a user's access entirely is DROP USER; changing what they
reach is another GRANT.
Administering is not something a stranger does
DEFINE USER ada ON prod.shop ROLE editor PASSWORD 'correct horse';
GRANT read ON users TO ada;
NotSignedIn — the store closed when ada was declared, and granting is
administering.
The order in which those two checks run is itself load-bearing:
GRANT read, write ON users FIELDS name TO ada;
Also NotSignedIn — not the field rule's own refusal. Identity is decided
before the statement's contents are, because a refusal naming the field rule
would have told a stranger that their statement parsed, which is a fact they are
not owed.
What is deliberately absent
There are no roles you define yourself, no groups, no inheritance and no deny rules. Three roles, two verbs, an optional field list, and one sentence deciding which of the two applies. Everything a deny rule expresses is expressible by granting less — and unlike a deny rule, a grant cannot interact with another grant to produce an outcome nobody predicted.