技能 效率工具 ClickUp企业RBAC与多工作区管理

ClickUp企业RBAC与多工作区管理

v20260423
clickup-enterprise-rbac
本技能包提供了ClickUp企业级的权限控制(RBAC)和多工作区访问功能。它实现了基于角色的权限管理校验(区分Owner、Admin、Member等),并指导开发人员如何使用OAuth 2.0流程,使得应用能够安全、可靠地连接和管理用户授权的多个工作区,适用场景包括需要精细化权限管理的SaaS应用开发。
获取技能
431 次下载
概览

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.

信息
Category 效率工具
Name clickup-enterprise-rbac
版本 v20260423
大小 6.17KB
更新时间 2026-04-26
语言