Skip to content
Back to skills

Figma Enterprise Rbac

ASecurity

'Configure Figma Enterprise features: OAuth 2.0, team management, and

  • 2,719 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 21, 2026
ai-agentstypescriptbashnodeexpressapi

Works with

  • claude code
  • cli
  • api

Security analysis

A100/100

Pro scans all 7 files and shows the line behind each finding

Scanned September 21, 2026

npx -y skills add jeremylongshore/claude-code-plugins-plus --skill figma-enterprise-rbac --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Figma Enterprise Rbac?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Figma Enterprise Rbac
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/jeremylongshore-figma-enterprise-rbac-3c0bfef4/badge)](https://www.skillsdirectory.com/skills/jeremylongshore-figma-enterprise-rbac-3c0bfef4)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: figma-enterprise-rbac
description: 'Configure Figma Enterprise features: OAuth 2.0, team management, and
  access control.

  Use when implementing OAuth flows, managing team/project access via API,

  or building Enterprise-level Figma integrations.

  Trigger with phrases like "figma enterprise", "figma OAuth",

  "figma team management", "figma access control", "figma SCIM".

  '
allowed-tools: Read, Write, Edit
version: 1.6.0
license: MIT
author: Jeremy Longshore <jeremy@intentsolutions.io>
tags:
- saas
- figma
compatibility: Designed for Claude Code
---
# Figma Enterprise RBAC

## Overview

Figma Enterprise features accessible via the REST API: OAuth 2.0 for user-facing apps, team/project management, and the Variables API (Enterprise-only). This skill covers building OAuth integrations and managing organizational access.

## Prerequisites

- Figma Enterprise or Organization plan
- OAuth app registered in Figma developer dashboard
- Understanding of OAuth 2.0 authorization code flow

## Instructions

### Step 1: OAuth 2.0 App Setup

```typescript
// Figma OAuth 2.0 Authorization Code Flow

// 1. Build authorization URL
function getAuthUrl(state: string): string {
  const params = new URLSearchParams({
    client_id: process.env.FIGMA_CLIENT_ID!,
    redirect_uri: process.env.FIGMA_REDIRECT_URI!,
    scope: 'file_content:read,file_comments:write,file_variables:read',
    state,
    response_type: 'code',
  });
  return `https://www.figma.com/oauth?${params}`;
}

// 2. Exchange authorization code for tokens (within 30 seconds!)
async function exchangeCode(code: string): Promise<{
  access_token: string;
  refresh_token: string;
  expires_in: number;
  user_id: string;
}> {
  const res = await fetch('https://api.figma.com/v1/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      client_id: process.env.FIGMA_CLIENT_ID!,
      client_secret: process.env.FIGMA_CLIENT_SECRET!,
      redirect_uri: process.env.FIGMA_REDIRECT_URI!,
      code,
      grant_type: 'authorization_code',
    }),
  });

  if (!res.ok) {
    const error = await res.text();
    throw new Error(`Token exchange failed: ${res.status} ${error}`);
  }

  return res.json();
}

// 3. Refresh expired tokens
async function refreshAccessToken(refreshToken: string): Promise<{
  access_token: string;
  expires_in: number;
}> {
  const res = await fetch('https://api.figma.com/v1/oauth/refresh', {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      client_id: process.env.FIGMA_CLIENT_ID!,
      client_secret: process.env.FIGMA_CLIENT_SECRET!,
      refresh_token: refreshToken,
    }),
  });

  if (!res.ok) throw new Error(`Token refresh failed: ${res.status}`);
  return res.json();
}
```

### Step 2: OAuth Callback Handler

```typescript
// Express callback handler
app.get('/auth/figma/callback', async (req, res) => {
  const { code, state } = req.query;

  // Verify state matches what we sent (CSRF protection)
  if (state !== req.session.oauthState) {
    return res.status(403).json({ error: 'Invalid state parameter' });
  }

  try {
    // Exchange code within 30 seconds
    const tokens = await exchangeCode(code as string);

    // Get user info with the new token
    const userRes = await fetch('https://api.figma.com/v1/me', {
      headers: { Authorization: `Bearer ${tokens.access_token}` },
    });
    const user = await userRes.json();

    // Store tokens securely (encrypted at rest)
    await saveUserTokens(user.id, {
      accessToken: tokens.access_token,
      refreshToken: tokens.refresh_token,
      expiresAt: new Date(Date.now() + tokens.expires_in * 1000),
    });

    res.redirect('/dashboard?connected=figma');
  } catch (error) {
    console.error('Figma OAuth error:', error);
    res.redirect('/settings?error=figma_auth_failed');
  }
});
```

### Step 3: Team and Project Management

```typescript
// GET /v1/teams/:team_id/projects -- list team projects
async function getTeamProjects(teamId: string, token: string) {
  const res = await fetch(
    `https://api.figma.com/v1/teams/${teamId}/projects`,
    { headers: { Authorization: `Bearer ${token}` } }
  );
  return res.json(); // { projects: [{ id, name }] }
}

// GET /v1/projects/:project_id/files -- list project files
async function getProjectFiles(projectId: string, token: string) {
  const res = await fetch(
    `https://api.figma.com/v1/projects/${projectId}/files`,
    { headers: { Authorization: `Bearer ${token}` } }
  );
  return res.json(); // { files: [{ key, name, thumbnail_url, last_modified }] }
}

// GET /v1/teams/:team_id/components -- published components (Tier 3)
async function getTeamComponents(teamId: string, token: string) {
  const res = await fetch(
    `https://api.figma.com/v1/teams/${teamId}/components`,
    { headers: { Authorization: `Bearer ${token}` } }
  );
  return res.json();
  // { meta: { components: [{ key, file_key, node_id, name, description }] } }
}

// GET /v1/teams/:team_id/styles -- published styles (Tier 3)
async function getTeamStyles(teamId: string, token: string) {
  const res = await fetch(
    `https://api.figma.com/v1/teams/${teamId}/styles`,
    { headers: { Authorization: `Bearer ${token}` } }
  );
  return res.json();
  // { meta: { styles: [{ key, file_key, node_id, name, style_type }] } }
}
```

### Step 4: Variables API (Enterprise Only)

```typescript
// GET /v1/files/:key/variables/local -- Tier 2, requires file_variables:read
async function getLocalVariables(fileKey: string, token: string) {
  const res = await fetch(
    `https://api.figma.com/v1/files/${fileKey}/variables/local`,
    { headers: { Authorization: `Bearer ${token}` } }
  );
  if (res.status === 403) {
    throw new Error('Variables API requires Figma Enterprise plan');
  }
  return res.json();
  // { meta: { variables: Record<id, Variable>, variableCollections: Record<id, Collection> } }
}

// GET /v1/files/:key/variables/published -- published variables
async function getPublishedVariables(fileKey: string, token: string) {
  const res = await fetch(
    `https://api.figma.com/v1/files/${fileKey}/variables/published`,
    { headers: { Authorization: `Bearer ${token}` } }
  );
  return res.json();
  // Published variables have a subscribed_id that changes each publish
}

// POST /v1/files/:key/variables -- bulk create/update/delete
async function updateVariables(
  fileKey: string,
  changes: VariableChanges,
  token: string
) {
  const res = await fetch(
    `https://api.figma.com/v1/files/${fileKey}/variables`,
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${token}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(changes),
    }
  );
  return res.json();
}
```

### Step 5: Access Control Middleware

```typescript
// Middleware that checks if user has Figma access to a resource
async function requireFigmaAccess(fileKey: string) {
  return async (req: Request, res: Response, next: NextFunction) => {
    const userToken = await getUserFigmaToken(req.user.id);
    if (!userToken) {
      return res.status(403).json({ error: 'Figma account not connected' });
    }

    // Check if user's token can access this file
    const check = await fetch(
      `https://api.figma.com/v1/files/${fileKey}?depth=1`,
      { headers: { Authorization: `Bearer ${userToken}` } }
    );

    if (check.status === 403) {
      return res.status(403).json({ error: 'No access to this Figma file' });
    }

    next();
  };
}
```

## Output

- OAuth 2.0 flow with authorization, token exchange, and refresh
- Team/project/file listing via API
- Variables API access (Enterprise)
- Access control middleware for file-level permissions

## Error Handling

| Error | Cause | Solution |
|-------|-------|----------|
| OAuth code expired | Exchange took >30s | Exchange immediately on callback |
| Token refresh failed | Refresh token revoked | Re-authenticate user through OAuth flow |
| 403 on Variables API | Not Enterprise plan | Use styles API instead (available on all plans) |
| Team components empty | No published components | Publish components in Figma first |

## Examples

Complete the OAuth flow locally and inspect the granted user (Steps 1-2):

```bash
# After the callback exchanges the code (POST /v1/oauth/token):
curl -s -H "Authorization: Bearer ${FIGMA_OAUTH_TOKEN}" https://api.figma.com/v1/me \
  | jq '{handle, email}'
# {"handle": "ops-bot", "email": "design-infra@example.com"}
```

List a project's files as that user — RBAC means you only see what the user can (Step 3):

```bash
curl -s -H "Authorization: Bearer ${FIGMA_OAUTH_TOKEN}" \
  "https://api.figma.com/v1/projects/${PROJECT_ID}/files" | jq '.files[].name'
```

A 403 here is working access control, not a bug — route it through the Step 5 middleware. Variables API (Enterprise-only) usage: `references/variables-api-enterprise-only.md`.

## Resources

- [Figma OAuth 2.0](https://developers.figma.com/docs/rest-api/authentication/)
- [Figma Variables API](https://developers.figma.com/docs/rest-api/variables-endpoints/)
- [Component Endpoints](https://developers.figma.com/docs/rest-api/component-endpoints/)

## Next Steps

For major migrations, see `figma-migration-deep-dive`.

Files in this skill

  • SKILL.md9.1 KB
  • references/access-control-middleware.md1 KB
  • references/errors.md718 B
  • references/oauth-2-0-app-setup.md2.1 KB
  • references/oauth-callback-handler.md1.3 KB
  • references/team-and-project-management.md1.7 KB
  • references/variables-api-enterprise-only.md1.7 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.