Role Assignment and Authorization

Overview

User roles are now managed exclusively through the Better Auth API on the Bun backend. The Go backend is read-only with respect to roles — it only queries and enforces them, never assigns or modifies them. There are two levels of roles:
  1. Platform Roles (managed by Better Auth admin plugin)
    • Applied globally to every user
    • Values: user, admin, superadmin
    • Stored in users.role column
  2. Organization Roles (managed by Better Auth organization plugin)
    • Applied per-organization
    • Values: owner, admin, staff, viewer, member
    • Stored in member.role column per organization

How Role Assignment Works

Platform Roles (Better Auth Admin Plugin)

When a user signs up via the Bun backend (POST /api/auth/sign-up):
  • Better Auth creates an entry in the users table
  • Platform role is initially set to "user" (default)
  • Superadmin can promote users to "admin" or "superadmin" via the admin plugin API
API Endpoints (Bun Backend):
  • POST /api/auth/admin/create-user — Create user with custom platform role
  • PATCH /api/auth/admin/update-user/:userId — Update user role
  • GET /api/auth/admin/users — List all users and their roles

Organization Roles (Better Auth Organization Plugin)

When a user is invited to or joins an organization:
  • Better Auth creates an entry in the member table
  • The inviter specifies the role (owner, admin, staff, viewer, member)
  • Organization owners can update member roles via the organization plugin API
API Endpoints (Bun Backend):
  • POST /api/auth/organization/create — Create organization (caller becomes owner)
  • POST /api/auth/organization/:id/members/invite — Invite member with specific role
  • PATCH /api/auth/organization/:id/members/:userId/update-role — Change member’s role
  • DELETE /api/auth/organization/:id/members/:userId — Remove member from org

How Go Backend Queries Roles

The Go backend never writes roles. Instead, it reads them on-demand or caches them.

User Repository (Platform Role)

Organization Repository (Org Role)


Authorization with Permission Service

Instead of checking roles directly, Go modules use the PermissionService for authorization. This service:
  1. Queries the member table for a user’s org role
  2. Maps the role to a permission set (owner → full perms, staff → limited perms, etc.)
  3. Caches the result for 5 minutes

Example: Checking Leave Approval Permission

This checks:
  • Both approver and employee are in the org
  • Approver has "leave:approve" permission
  • If approver is not an admin, they must be the employee’s direct manager

Permission Mappings

Org roles map to permissions as follows: Permissions include:
  • data:read, data:write — Data access
  • leave:approve, leave:request — Leave management
  • member:invite, member:manage, member:remove — Team management
  • org:manage — Organization settings

Caching and Consistency

Permission Cache

The PermissionService caches role-to-permission lookups with a 5-minute TTL:

Real-time Consistency (NATS)

To achieve real-time consistency despite caching, the Bun backend publishes role-change events to NATS. The Go backend’s MemberRoleChangeConsumer subscribes to these and invalidates the cache immediately:
  1. Member Role Changed: InvalidateMemberCache(userID, orgID)
  2. Member Removed: InvalidateMemberCache(userID, orgID)
  3. Member Added: InvalidateMemberCache(userID, orgID)

Performance Optimization (Postgres Indexes)

Specialized indexes are added to the shared PostgreSQL database to ensure permission checks remain fast (sub-millisecond):
  • idx_users_role: ON users(role) — Optimizes platform permission check
  • idx_members_role: ON members(role) — Optimizes fetching members by role
  • idx_members_org_role: ON members(organization_id, role) — Primary index for role-to-permission lookups

How to Assign Roles

As a Developer

You cannot assign roles from the Go backend. All role changes must be done via the Better Auth API on the Bun backend:
  1. Add user to organization with role:
  2. Update user’s organization role:

As a User

In the frontend, go to Settings → Members (org admin only) and:
  • Invite new members with a specific role
  • Change existing members’ roles
  • Remove members from the organization

Testing

Test: Query User Role from Go

Test: Query Organization Members from Go

Test: Authorization Check in Go


Key Differences from Previous Architecture