> clickup-enterprise-rbac
Implement ClickUp Enterprise SSO, OAuth 2.0 multi-workspace access, role-based permissions, and organization management via API v2. Trigger: "clickup SSO", "clickup RBAC", "clickup enterprise", "clickup roles", "clickup permissions", "clickup OAuth app", "clickup multi-workspace".
curl "https://skillshub.wtf/jeremylongshore/claude-code-plugins-plus-skills/clickup-enterprise-rbac?format=md"ClickUp Enterprise RBAC
Overview
Enterprise access patterns for ClickUp API v2. ClickUp's role system is built into the workspace, and the API surfaces roles via member objects. OAuth 2.0 enables multi-workspace apps where each user authorizes their own workspaces.
ClickUp Role Model
ClickUp workspace members have role IDs in the API:
| Role ID | Role | Permissions |
|---|---|---|
| 1 | Owner | Full control, billing, workspace settings |
| 2 | Admin | Manage members, spaces, integrations |
| 3 | Member | Create/edit tasks, spaces (per permission) |
| 4 | Guest | Limited access to shared items only |
// Get workspace members with roles
async function getWorkspaceMembers(teamId: string) {
const data = await clickupRequest(`/team/${teamId}`);
return data.team.members.map((m: any) => ({
userId: m.user.id,
username: m.user.username,
email: m.user.email,
role: m.user.role, // 1=owner, 2=admin, 3=member, 4=guest
roleLabel: { 1: 'owner', 2: 'admin', 3: 'member', 4: 'guest' }[m.user.role],
}));
}
// Check if user can perform admin operations
function canAdminister(member: { role: number }): boolean {
return member.role <= 2; // Owner or Admin
}
OAuth 2.0 Multi-Workspace App
Build apps that access multiple ClickUp workspaces on behalf of users.
// Step 1: Redirect user to ClickUp authorization
function getOAuthUrl(state: string): string {
return `https://app.clickup.com/api?client_id=${process.env.CLICKUP_CLIENT_ID}&redirect_uri=${encodeURIComponent(process.env.CLICKUP_REDIRECT_URI!)}&state=${state}`;
}
// Step 2: Exchange code for token
async function handleOAuthCallback(code: string) {
const response = await fetch('https://api.clickup.com/api/v2/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: process.env.CLICKUP_CLIENT_ID,
client_secret: process.env.CLICKUP_CLIENT_SECRET,
code,
}),
});
const { access_token } = await response.json();
// Step 3: Discover which workspaces user authorized
const teamsResponse = await fetch('https://api.clickup.com/api/v2/team', {
headers: { 'Authorization': access_token },
});
const { teams } = await teamsResponse.json();
return {
token: access_token, // Doesn't expire (but can be revoked)
workspaces: teams.map((t: any) => ({ id: t.id, name: t.name })),
};
}
// Step 4: Store per-user tokens
interface UserClickUpAuth {
userId: string;
clickupToken: string; // Encrypt at rest
authorizedWorkspaces: string[];
connectedAt: Date;
}
Permission Middleware
// Express middleware that checks ClickUp workspace access
function requireClickUpAccess(requiredRole: number = 3) {
return async (req: any, res: any, next: any) => {
const userToken = req.user.clickupToken;
const teamId = req.params.teamId || req.body.teamId;
if (!userToken) {
return res.status(401).json({ error: 'ClickUp not connected' });
}
// Verify user still has access to this workspace
const teamsRes = await fetch('https://api.clickup.com/api/v2/team', {
headers: { 'Authorization': userToken },
});
if (!teamsRes.ok) {
return res.status(401).json({ error: 'ClickUp token expired or revoked' });
}
const { teams } = await teamsRes.json();
const workspace = teams.find((t: any) => t.id === teamId);
if (!workspace) {
return res.status(403).json({ error: 'No access to this ClickUp workspace' });
}
// Check role level
const userMember = workspace.members.find(
(m: any) => m.user.id === req.user.clickupUserId
);
if (!userMember || userMember.user.role > requiredRole) {
return res.status(403).json({
error: `Requires role ${requiredRole} or higher`,
});
}
req.clickupWorkspace = workspace;
next();
};
}
// Usage
app.delete('/api/clickup/:teamId/space/:spaceId',
requireClickUpAccess(2), // Admin required
async (req, res) => { /* ... */ }
);
User Groups (API v2 "Teams")
GET /api/v2/group Get User Groups
POST /api/v2/team/{team_id}/group Create User Group
PUT /api/v2/group/{group_id} Update User Group
DELETE /api/v2/group/{group_id} Delete User Group
// Create a user group for engineering team
await clickupRequest(`/team/${teamId}/group`, {
method: 'POST',
body: JSON.stringify({
name: 'Engineering',
member_ids: [183, 456, 789],
}),
});
Audit Trail
interface ClickUpAuditEntry {
timestamp: string;
userId: number;
workspaceId: string;
action: string;
resource: string;
resourceId: string;
success: boolean;
}
function logClickUpAction(entry: Omit<ClickUpAuditEntry, 'timestamp'>): void {
const log: ClickUpAuditEntry = {
...entry,
timestamp: new Date().toISOString(),
};
console.log(JSON.stringify({ level: 'audit', service: 'clickup', ...log }));
}
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| OAUTH_023/027 | Workspace not authorized | User must re-authorize via OAuth flow |
| Role check fails | User role changed in ClickUp | Re-fetch member data from API |
| Token revoked | User disconnected app | Handle 401, prompt re-auth |
| Guest access denied | Endpoint requires member+ | Check role field before API call |
Resources
Next Steps
For major migrations, see clickup-migration-deep-dive.
> related_skills --same-repo
> fathom-cost-tuning
Optimize Fathom API usage and plan selection. Trigger with phrases like "fathom cost", "fathom pricing", "fathom plan".
> fathom-core-workflow-b
Sync Fathom meeting data to CRM and build automated follow-up workflows. Use when integrating Fathom with Salesforce, HubSpot, or custom CRMs, or creating automated post-meeting email summaries. Trigger with phrases like "fathom crm sync", "fathom salesforce", "fathom follow-up", "fathom post-meeting workflow".
> fathom-core-workflow-a
Build a meeting analytics pipeline with Fathom transcripts and summaries. Use when extracting insights from meetings, building CRM sync, or creating automated meeting follow-up workflows. Trigger with phrases like "fathom analytics", "fathom meeting pipeline", "fathom transcript analysis", "fathom action items sync".
> fathom-common-errors
Diagnose and fix Fathom API errors including auth failures and missing data. Use when API calls fail, transcripts are empty, or webhooks are not firing. Trigger with phrases like "fathom error", "fathom not working", "fathom api failure", "fix fathom".