> For the complete documentation index, see [llms.txt](https://he-said.tdreyno.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://he-said.tdreyno.com/conceptual-from-scratch/rbac-implementation.md).

# Implementing RBAC

This is the conceptual/core-algebra RBAC implementation guide. For the dedicated RBAC facade package, see [RBAC Guide](/package-guides/rbac-guide.md) and [RBAC API Reference](/package-guides/rbac-api.md). If you're starting from scratch, prefer `@tdreyno/he-said/rbac` and use this page when you need the underlying relation-based model.

This guide shows a simple, real-world RBAC model in he-said.

Scenario:

* A company has workspaces.
* Users have a role inside each workspace.
* Roles are `owner`, `manager`, or `member`.
* Only owners and managers can invite users.
* Owners can manage billing.
* Project editors can edit projects they own.

The example keeps RBAC explicit and concrete. No generic "ability" term is needed.

## Domain Model

### Types

```ts
type Role = "owner" | "manager" | "member"

type User = { id: string }
type Workspace = { id: string }
type Project = { id: string; workspaceId: string; ownerId: string }
```

### Terms and Relations

```ts
import { and, eq, oneOf, or, relation, term } from "@tdreyno/he-said"

const actor = term<User>()
const role = term<Role>()
const workspace = term<Workspace>()
const project = term<Project>()

const userInWorkspace = relation<User, Workspace>()
const userHasWorkspaceRole = relation<User, Role>()
const projectInWorkspace = relation<Project, Workspace>()
const projectOwnedBy = relation<Project, User>()
```

## RBAC Rules

This section maps plain business rules directly into policy rules.

```ts
const canInviteUsers = and(
  userInWorkspace(actor, workspace),
  userHasWorkspaceRole(actor, oneOf(role, ["owner", "manager"])),
)

const canManageBilling = and(
  userInWorkspace(actor, workspace),
  userHasWorkspaceRole(actor, eq(role, "owner")),
)

const canEditProject = and(
  projectInWorkspace(project, workspace),
  userInWorkspace(actor, workspace),
  or(
    userHasWorkspaceRole(actor, eq(role, "owner")),
    and(
      userHasWorkspaceRole(actor, eq(role, "manager")),
      projectOwnedBy(project, actor),
    ),
  ),
)
```

## Suggested Migration Path

1. Start with one business action, like `invite users`.
2. Write one explicit rule with role checks and scope checks.
3. Add facts from your existing membership tables.
4. Replace one endpoint-level `if role === ...` block at a time.
5. Add resource ownership rules where needed.

## Common Pitfalls

* Encoding role checks in application code and data checks in policy code.
* Forgetting workspace scoping while checking roles.
* Modeling ownership as a predicate when it is a relation in your database.

## Practical Rule of Thumb

Keep your RBAC language from the product domain:

* Roles answer who can do this in general.
* Relations answer whether they can do it on this specific resource.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://he-said.tdreyno.com/conceptual-from-scratch/rbac-implementation.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
