Permissions API

Roles and Permissionsfor Every Route

Name your permissions, grant them per organization and declare a gate on each route. The platform decides every request before your code runs.

Caller
  1. GET /products public 200 Handler runs 200 Handler runs 200 Handler runs 200 Handler runs 200 Handler runs
  2. GET /orders/mine auth 401 CREDENTIAL_REQUIRED 200 Handler runs 200 Handler runs 200 Handler runs 200 Handler runs
  3. POST /orders verified 401 CREDENTIAL_REQUIRED 200 Handler runs 200 Handler runs 200 Handler runs 200 Handler runs
  4. GET /reports auth:ADMIN 401 CREDENTIAL_REQUIRED 403 PERMISSION_DENIED 200 Handler runs 200 Handler runs 403 PERMISSION_DENIED
  5. GET /contact-requests owner 401 CREDENTIAL_REQUIRED 403 PERMISSION_DENIED 403 PERMISSION_DENIED 200 Handler runs 403 PERMISSION_DENIED

Decided by the platform before your code runs.

Route Gates

public, auth, verified, owner, auth:PERMISSION and auth?PERMISSION, written next to each route. A caller the gate refuses gets 401 or 403, and your handler never runs.

routes.json
[
  "GET /products public",
  "GET /orders/mine auth",
  "POST /orders verified",
  "GET /reports auth:ADMIN",
  "GET /hosts/mine auth?ADMIN",
  "GET /contact-requests owner"
]

A Permission Catalog

Up to 64 named permissions per app, with implications such as ADMIN granting WRITE and READ. The catalog is append only, so a stored grant never changes meaning.

ADMIN WRITE READ
stores/berlin ADMIN stores/austin WRITE stores/osaka READ

Organizations and Memberships

Grant permissions inside one organization: a team, a store, a customer account. auth:[email protected] checks the organization the path names.

routes.json
[
  "GET /orgs/:org/notes auth:[email protected]",
  "GET /notes auth:EDIT@orgs.?org",
  "GET /dashboard auth:EDIT@*"
]

Checks Inside a Handler

When the organization is on a row your handler reads, db.requirePermission checks it and answers with the platform's own refusal.

functions/notes.js
const NOTES_EDIT = db.permission('NOTES_EDIT');

module.exports = async function (request) {
  const note = db.collection('notes').get(request.params.id);
  db.requirePermission(NOTES_EDIT, request.auth, note.team);
  // only a caller who may edit this team's notes gets here
};

Keys for Your Customers

Your customers' keys call your auth routes. A permission route answers only your own account's key, and an owner route answers nobody else.

Account keys at the gate
GET /orders/mine auth        customer key  200
GET /reports auth:ADMIN     customer key  403
GET /reports auth:ADMIN     your key      200
GET /contact-requests owner your key      200

Collection Rules

allow, auth, owner, role or deny for each of read, create, write and delete, compiled once into flags.

collections/posts.json
{
  "rules": {
    "read": "allow",
    "write": "role:editor",
    "create": "auth",
    "delete": "role:admin"
  }
}
Named permissions per app
64
AND per permission check
1
Membership read per organization gate
1
Route gate words
6