Amba

Roles & Permissions

Model custom roles and per-user permissions on top of Amba — scope your app's own access control without building an auth service.

Amba's end-user auth is about identity (who is this user?). Roles are about authorization (what is this user allowed to do inside the app?). If your app needs admin users, moderators, group owners, or any kind of tiered permissions, the roles API is where you model it.

Roles live in your project's database. They're per-project, per-user, and intentionally flexible — the permissions field is a JSONB array your app interprets however it wants.

Data model

Tables:

TablePurpose
rolesname, description, permissions (JSONB array)
user_rolesapp_user_id, role_id, assigned_by

The permissions array is opaque to Amba — your app decides what ["content.moderate", "users.ban"] means. Typical patterns:

  • Permission strings ("feed.post", "feed.delete_any")
  • Scopes ("read:billing", "write:billing")
  • Named capabilities ("premium_features", "beta_cohort")

Creating a role

POST /admin/roles
 
{
  "name": "moderator",
  "description": "Can remove posts and ban users",
  "permissions": ["content.moderate", "users.ban"]
}

Response:

{
  "data": {
    "id": "<uuid>",
    "name": "moderator",
    "description": "Can remove posts and ban users",
    "permissions": ["content.moderate", "users.ban"],
    "created_at": "...",
    "updated_at": "..."
  }
}

Role names are unique per project.

Updating a role

PATCH with any subset of name, description, permissions:

PATCH /admin/roles/:roleId
 
{ "permissions": ["content.moderate", "users.ban", "feed.pin"] }

Assigning a role

POST /admin/roles/assign
 
{ "app_user_id": "<uuid>", "role_id": "<uuid>" }

A single user can have multiple roles. Duplicate assignments are rejected by the user_roles primary key; catch that on the client side.

Revoking a role

POST /admin/roles/revoke
 
{ "app_user_id": "<uuid>", "role_id": "<uuid>" }

Idempotent — revoking a role a user doesn't have still returns 200 { data: { revoked: true } }.

Listing users in a role

GET /admin/roles/:roleId/users

Returns user_roles rows joined with app_users minimal shape (id, display_name, email).

Checking roles from the client SDK

const roles = await client.roles.getMy();
// UserRole[] — the current user's role assignments

Build your own hasPermission(permission) helper around this. Amba won't police permission strings for you — interpretation lives in your app code:

async function hasPermission(permission: string): Promise<boolean> {
  const roles = await client.roles.getMy();
  return roles.some(
    (r) => Array.isArray(r.role?.permissions) && r.role.permissions.includes(permission),
  );
}

Patterns

Keep role definitions small. Add roles as you add features; don't pre-invent every future role. Renaming is supported, deletion cascades the user_roles rows.

Use segments for cohort targeting, not roles. "All users in cohort X" is a segment. "User has elevated permissions" is a role. Don't conflate them.

Roles are not billed tier. Use entitlements for paid features — entitlements sync from RevenueCat and respect subscription lifecycle. A "premium" role won't update when a subscription lapses; a premium entitlement will.

Routes reference

MethodPathDescription
POST/admin/rolesCreate a role
GET/admin/rolesList roles
PATCH/admin/roles/:roleIdUpdate a role
DELETE/admin/roles/:roleIdDelete a role
POST/admin/roles/assignAssign role to user
POST/admin/roles/revokeRevoke role from user
GET/admin/roles/:roleId/usersList users with a specific role
  • Entitlements — subscription state (vs. role-based permissions).
  • Auth — identity (vs. authorization).
  • Segments — cohort targeting.

On this page