| name | gamma-enterprise-rbac |
| description | Implement enterprise role-based access control for Gamma integrations.
Use when configuring team permissions, multi-tenant access,
or enterprise authorization patterns.
Trigger with phrases like "gamma RBAC", "gamma permissions",
"gamma access control", "gamma enterprise", "gamma roles".
|
| allowed-tools | Read, Write, Edit |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
Gamma Enterprise RBAC
Overview
Implement enterprise-grade role-based access control for Gamma integrations with multi-tenant support.
Prerequisites
- Enterprise Gamma subscription
- Identity provider (IdP) integration
- Database for permission storage
- Understanding of RBAC concepts
RBAC Model
Role Hierarchy
Organization Admin
└── Workspace Admin
└── Team Lead
└── Editor
└── Viewer
Permission Matrix
| Permission | Viewer | Editor | Team Lead | Workspace Admin | Org Admin |
|---|
| View presentations | Yes | Yes | Yes | Yes | Yes |
| Create presentations | No | Yes | Yes | Yes | Yes |
| Edit own presentations | No | Yes | Yes | Yes | Yes |
| Edit team presentations | No | No | Yes | Yes | Yes |
| Delete presentations | No | No | Yes | Yes | Yes |
| Manage team members | No | No | Yes | Yes | Yes |
| Manage workspace | No | No | No | Yes | Yes |
| Manage billing | No | No | No | No | Yes |
| Manage API keys | No | No | No | No | Yes |
Instructions
Step 1: Define Roles and Permissions
enum Permission {
PRESENTATION_VIEW = 'presentation:view',
PRESENTATION_CREATE = 'presentation:create',
PRESENTATION_EDIT_OWN = 'presentation:edit:own',
PRESENTATION_EDIT_TEAM = 'presentation:edit:team',
PRESENTATION_EDIT_ALL = 'presentation:edit:all',
PRESENTATION_DELETE = 'presentation:delete',
PRESENTATION_EXPORT = 'presentation:export',
TEAM_VIEW = 'team:view',
TEAM_MANAGE = 'team:manage',
WORKSPACE_VIEW = 'workspace:view',
WORKSPACE_MANAGE = 'workspace:manage',
BILLING_VIEW = 'billing:view',
BILLING_MANAGE = 'billing:manage',
API_KEYS_MANAGE = 'api_keys:manage',
}
interface Role {
name: string;
permissions: Permission[];
inherits?: string;
}
const roles: Record<, > = {
: {
: ,
: [
.,
.,
.,
],
},
: {
: ,
: [
.,
.,
.,
],
: ,
},
: {
: ,
: [
.,
.,
.,
],
: ,
},
: {
: ,
: [
.,
.,
.,
],
: ,
},
: {
: ,
: [
.,
.,
],
: ,
},
};
Step 2: Permission Resolution
class RBACService {
private rolePermissions: Map<string, Set<Permission>> = new Map();
constructor() {
this.resolveRoleHierarchy();
}
private resolveRoleHierarchy() {
const resolve = (roleName: string): Set<Permission> => {
if (this.rolePermissions.has(roleName)) {
return this.rolePermissions.get(roleName)!;
}
const role = roles[roleName];
const permissions = new Set<Permission>(role.permissions);
if (role.inherits) {
const inherited = resolve(role.inherits);
inherited.forEach(p => permissions.add(p));
}
this.rolePermissions.set(roleName, permissions);
permissions;
};
.(roles).(resolve);
}
(: , : ): {
permissions = ..(userRole);
permissions?.(permission) ?? ;
}
(: ): [] {
.(..(userRole) ?? []);
}
}
rbac = ();
Step 3: Authorization Middleware
import { rbac } from '../services/rbac-service';
function authorize(...requiredPermissions: Permission[]) {
return async (req: Request, res: Response, next: NextFunction) => {
const user = req.user;
if (!user) {
return res.status(401).json({ error: 'Unauthorized' });
}
const userRole = await getUserRole(user.id, req.params.workspaceId);
const hasAllPermissions = requiredPermissions.every(permission =>
rbac.hasPermission(userRole, permission)
);
if (!hasAllPermissions) {
return res.status(403).json({
error: 'Forbidden',
required: requiredPermissions,
userRole,
});
}
next();
};
}
app.post('/api/presentations',
(.),
(req, res) => {
presentation = gamma..(req.);
res.(presentation);
}
);
app.(,
(.),
(req, res) => {
gamma..(req..);
res.().();
}
);
Step 4: Resource-Level Authorization
interface ResourcePolicy {
action: string;
conditions: (user: User, resource: any) => boolean;
}
const presentationPolicies: ResourcePolicy[] = [
{
action: 'edit',
conditions: (user, presentation) => {
if (presentation.ownerId === user.id) return true;
if (user.role === 'team_lead' && presentation.teamId === user.teamId) {
return true;
}
if (user.role === 'workspace_admin' || user.role === 'org_admin') {
return true;
}
return false;
},
},
];
async function canPerformAction(
user: User,
: ,
:
): <> {
policy = presentationPolicies.( p. === action);
policy?.(user, resource) ?? ;
}
app.(, (req, res) => {
presentation = db..({
: { : req.. },
});
(! (req., , presentation)) {
res.().({ : });
}
});
Step 5: Multi-Tenant Isolation
async function tenantIsolation(req: Request, res: Response, next: NextFunction) {
const user = req.user;
const workspaceId = req.params.workspaceId || req.headers['x-workspace-id'];
const membership = await db.workspaceMemberships.findUnique({
where: {
userId_workspaceId: {
userId: user.id,
workspaceId: workspaceId,
},
},
});
if (!membership) {
return res.status(403).json({ error: 'Not a member of this workspace' });
}
req.workspace = await db.workspaces.findUnique({
where: { id: workspaceId },
});
req.userRole = membership.role;
next();
}
app.use('/api/workspaces/:workspaceId', tenantIsolation);
Step 6: Audit Authorization Events
async function logAuthorizationEvent(
userId: string,
action: string,
resource: string,
resourceId: string,
granted: boolean,
reason?: string
) {
await db.authAuditLog.create({
data: {
userId,
action,
resource,
resourceId,
granted,
reason,
timestamp: new Date(),
},
});
if (!granted) {
metrics.increment('authorization.denied', {
action,
resource,
});
}
}
Resources
Next Steps
Proceed to gamma-migration-deep-dive for migration strategies.