RBAC & Roles
GTM Clarity uses Clerk Organizations for role-based access control. Each user within a tenant is assigned one of three roles that govern what they can see and do.
Role Definitions
| Role | Clerk Value | Description |
|---|---|---|
| Admin | org:admin | Full access. Manages connectors, scoring config, team members, and all settings. |
| Manager | org:manager | Operational access. Can trigger syncs, view scores, and manage field mappings. |
| Viewer | org:viewer | Read-only access. Can view dashboards, scores, and reports. |
Permission Matrix
| Operation | Admin | Manager | Viewer |
|---|---|---|---|
| View dashboards and scores | Yes | Yes | Yes |
| View audit logs | Yes | Yes | Yes |
| View connector status | Yes | Yes | Yes |
| Trigger manual sync | Yes | Yes | No |
| Edit field mappings | Yes | Yes | No |
| Confirm buying group roles | Yes | Yes | No |
| Create/edit scoring config | Yes | No | No |
| Add/remove connectors | Yes | No | No |
| Manage OAuth connections | Yes | No | No |
| Enable/disable writeback | Yes | No | No |
| Invite/remove team members | Yes | No | No |
| Change user roles | Yes | No | No |
| Manage role templates | Yes | No | No |
| Delete tenant data | Yes | No | No |
How Roles Are Enforced
Server-Side Enforcement
Role checks happen on the server via the requireRole and hasRole helpers in src/lib/auth.ts:
import { auth } from "@clerk/nextjs/server";
import type { OrgRole } from "@/types/tenant";
export async function requireRole(role: OrgRole): Promise<void> {
const session = await auth();
if (!session.orgRole || session.orgRole !== role) {
throw new Error(`Insufficient permissions: requires ${role}`);
}
}
export async function hasRole(role: OrgRole): Promise<boolean> {
const session = await auth();
return session.orgRole === role;
}
tRPC Middleware
The tRPC layer enforces RBAC through dedicated middleware in src/server/trpc/middleware/rbac.ts. Mutation procedures that modify scoring configuration, connectors, or team settings require the org:admin role. The middleware reads the role from the Clerk session attached to every request.
Role definitions are declared as the TypeScript union type OrgRole:
export type OrgRole = "org:admin" | "org:manager" | "org:viewer";
Assigning Roles
Via the Dashboard
- Navigate to Settings > Team
- Locate the user in the member list
- Click the role dropdown and select the new role
- The change takes effect immediately on the next request
Via Clerk Dashboard
- Open the Clerk Dashboard
- Go to Organizations > [Your Org] > Members
- Click the member and change their role
- Save changes
When onboarding a new team, assign the first user as org:admin. That admin can then invite the rest of the team with appropriate roles directly from GTM Clarity.
Admin-Only Operations
The following operations are restricted to the org:admin role and are logged in the audit trail:
- Connector management -- Adding, editing, or removing data source connections
- OAuth authorization -- Initiating OAuth flows for Salesforce, O365, etc.
- Scoring configuration -- Changing ICP profiles, weights, thresholds, and decay settings
- Writeback control -- Enabling or disabling score pushback to CRM
- Team management -- Inviting users, removing users, changing roles
- Role template management -- Creating or editing buying group role templates
- Tenant settings -- Modifying tenant-level configuration
All mutations performed by any role are recorded in the audit_log table. This includes the userId, action, resource, and full changes payload. See Audit Logs for details.
Related Pages
- Tenant Setup -- Creating and configuring tenants
- Audit Logs -- Reviewing the audit trail
- Connector Management -- Managing data sources
- Scoring Configuration -- Configuring the scoring engine