06 — Permissions
Chapter 06 — Permissions
Section titled “Chapter 06 — Permissions”Not everyone in an org should be able to do everything. This chapter adds role-based access control (RBAC): owners can delete projects, members can only view.
How roles work
Section titled “How roles work”Every org member has a role: owner or member. The role is stored on the membership record and surfaced on ctx.org.member.role inside orgProcedure.
CruzJS uses permission strings like projects:delete. You define which roles have which permissions, then check them in your procedures.
Define permissions
Section titled “Define permissions”Create packages/core/src/tasks/tasks.permissions.ts:
import { definePermissions } from '@cruzjs/core';
export const TASK_PERMISSIONS = definePermissions({ 'projects:create': ['owner', 'member'], 'projects:delete': ['owner'], 'tasks:create': ['owner', 'member'], 'tasks:delete': ['owner', 'member'],});Enforce in the router
Section titled “Enforce in the router”import { requirePermission } from '@cruzjs/core';import { TASK_PERMISSIONS } from './tasks.permissions';
deleteProject: t.orgProcedure .input(z.object({ id: z.string() })) .mutation(({ ctx, input }) => { requirePermission(ctx.org, 'projects:delete', TASK_PERMISSIONS); return this.service.deleteProject(input.id, ctx.org.id); }),requirePermission throws a 403 TRPCError if the caller’s role doesn’t have the permission. No if statement needed in your service.
Test with two accounts
Section titled “Test with two accounts”- Sign in as the org owner. Try deleting a project — it works.
- Sign in as a member. Try deleting the same project — you get a 403.
The check happens server-side. The client cannot bypass it by calling the endpoint directly.
Conditional UI
Section titled “Conditional UI”Hide the delete button for members:
// In your React componentconst { data: member } = trpc.org.currentMember.useQuery();
{member?.role === 'owner' && ( <button onClick={() => deleteProject.mutate({ id: project.id })}> Delete project </button>)}Always enforce on the server too — the UI check is just UX, not security.
What we built
Section titled “What we built”- Defined permission strings for
projects:delete - Used
requirePermissionto enforce roles server-side - Tested the access control with two accounts
Next: Chapter 07 — Real-Time