Skip to content

Actions and resources ​

← Documentation home

Sentinel separates what kind of thing you are touching (resource) from what you want to do (action). Together they form a permission check: can this subject perform this action on this resource?


Resources ​

A resource is a category in your domain, not a specific database row:

  • "invoice" — any invoice-shaped object
  • "project"
  • "settings"

The resource argument to evaluate() is the type. Instance-specific data (invoice id, owner, status) goes in resourceContext.

typescript
engine.evaluate(user, "invoice:approve", "invoice", {
  id: "inv_123",
  ownerId: "user-42",
  status: "pending",
});

Why split type and context: Rules often apply to all invoices of a type (on("invoice")) while conditions inspect the particular instance (ownerId, status).


Actions ​

Actions use the resource:verb convention:

ActionMeaning
invoice:approveApprove an invoice
invoice:sendSend an invoice to a customer
project:archiveArchive a project
user:impersonateImpersonate another user

Verbs are domain language, not HTTP methods and not CRUD unless CRUD is genuinely your model.

Why not CRUD? ​

update does not distinguish "edit draft" from "approve final version." Separate actions make policies precise and audit logs readable.


Wildcards ​

Rules can match action patterns:

typescript
allow()
  .roles("manager")
  .actions("invoice:*")
  .on("invoice")
  .build();

Patterns compile to regex at addRule() time. See Wildcard actions.


Actions vs HTTP routes ​

One HTTP route should map to one action:

POST /invoices/:id/approve  →  action: invoice:approve, resource: invoice
DELETE /projects/:id        →  action: project:archive, resource: project

Do not reuse a generic "write" action across unrelated endpoints — you lose granularity in policies and audits.


Released under the MIT License.