TheShipStack Docs
Features

RBAC

Role-based access control via Better Auth's access control plugin.

TheShipStack uses Better Auth's access control plugin to enforce permissions across the entire app — in server actions, API routes, and the UI.

Roles

RoleWhoPermissions
ownerWorkspace creatorFull access — update, delete workspace; manage billing; manage members and invitations; all project actions
adminInvited as adminUpdate workspace; manage members and invitations; all project actions; read billing
memberInvited as memberCreate and update projects only

Permissions by resource

ResourceActionsowneradminmember
organizationupdate, delete✓ / ✓✓ / —— / —
invitationcreate, cancel
memberupdate, delete
projectcreate, update, deletecreate / update
billingread, manageread

Checking permissions in server actions

Use requirePermission from lib/require-org.ts. It throws 'Forbidden' if the current user lacks the permission:

import { requirePermission } from '@/lib/require-org'

export async function deleteProject(id: string) {
  await requirePermission('project', 'delete')
  // ... safe to proceed
}

Checking permissions in server components

Use auth.api.hasPermission for conditional UI rendering:

import { auth } from '@/lib/auth'
import { headers } from 'next/headers'

const canManageBilling = await auth.api
  .hasPermission({
    headers: await headers(),
    body: { permissions: { billing: ['manage'] } },
  })
  .then((r) => r.success)

UI enforcement

The UI shows all actions but disables them with a tooltip for unauthorized users — except the danger zone tab, which is hidden entirely from non-owners. This gives every user a clear picture of what's possible without exposing destructive controls.

Customizing roles

The role definitions live in lib/permissions.ts. To add a new resource or action:

  1. Add it to the statement object
  2. Grant it to the appropriate roles in memberRole, adminRole, or ownerRole
  3. Register the updated ac in lib/auth.ts and lib/auth-client.ts
// lib/permissions.ts
export const statement = {
  organization: ['update', 'delete'],
  invitation: ['create', 'cancel'],
  member: ['update', 'delete'],
  project: ['create', 'update', 'delete'],
  billing: ['read', 'manage'],
  // add your resource here
  report: ['create', 'view', 'delete'],
} as const

On this page