Getting started
Install
Section titled “Install”Rolebook is a private preview and is not yet on a public registry. Once publishing is enabled:
bun add rolebookThe package is plain ESM with TypeScript declarations and runs on any modern JavaScript runtime.
1. Define a policy
Section titled “1. Define a policy”Resources declare their concrete actions and one optional parent type. Roles live at a scope and hold allow and deny rules. Define the policy once and reuse the returned object: it is immutable, and its compiled form is cached by identity.
import { definePolicy } from "rolebook";
export const policy = definePolicy({ version: "4.0.0", resources: { organization: { actions: ["read"] }, workspace: { parent: "organization", actions: ["read", "update"] }, project: { parent: "workspace", actions: ["read", "update", "delete"] }, }, roles: { workspace_editor: { scope: "workspace", rules: [ { effect: "allow", permission: "project:read" }, { effect: "allow", permission: "project:update" }, ], }, },});2. Bind the request
Section titled “2. Bind the request”Bind the authenticated subject together with the scoped assignments your application loaded for this request. The subject never carries roles.
import { createAuthorizer } from "rolebook";
const authorization = createAuthorizer(policy).bind({ subject: { type: "user", id: "user_123" }, assignments: [ { subject: { type: "user", id: "user_123" }, role: "workspace_editor", scope: { resource: { type: "workspace", id: "ws_456" }, appliesTo: "descendants", }, }, ],});3. Check against a trusted resource
Section titled “3. Check against a trusted resource”Load the resource through your authoritative, tenant-scoped path, then snapshot it with its complete ancestry, from immediate parent to root.
import { trustedResource } from "rolebook";
const project = trustedResource( { type: "project", id: "proj_1" }, [ { type: "workspace", id: "ws_456" }, { type: "organization", id: "org_1" }, ], { ownerId: "user_123", status: "draft" },);
const decision = authorization.check({ permission: "project:update", resource: project });decision.allowed; // truedecision.code; // "ALLOWED"check() never throws for malformed input. It returns a closed decision with a stable code instead. Use enforce() to throw on denial and explain() for a rule trace. See Decisions.
- Policies for inheritance, wildcards, and scope rules.
- Hono adapter to guard routes.