Skip to content
Skillv1.0.0

figma-enterprise-rbac

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 integra

by jeremylongshore(0) 0 installs
Free
Sign in to install

Free account. Installing gives you the manifest plus copy-paste snippets.

See reviews

About

Imported from jeremylongshore/tons-of-skills-marketplace (skills/.curated/figma-enterprise-rbac/SKILL.md). Install upstream with npx skills add jeremylongshore/tons-of-skills-marketplace --skill figma-enterprise-rbac. Copyright stays with the author (MIT).

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

// 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

// 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

// 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)

// 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

// 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):

# 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):

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

Next Steps

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

Use it

Copy one of these into your project. Installing also returns the manifest and these snippets.

yaml
targets:
  - https://api.opensmartroute.ai/api/v1/registry/jeremylongshore-tons-of-skills-marketplace-figma-enterpr-ed741d/manifest   # or paste the manifest below

Manifest

An Open Capability Manifest: the router reads it to know what this does, what it costs and when to pick it.

jeremylongshore-tons-of-skills-marketplace-figma-enterpr-ed741d.ocm.jsonjson
{
  "ocm": "1",
  "id": "jeremylongshore-tons-of-skills-marketplace-figma-enterpr-ed741d",
  "kind": "skill",
  "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\".",
  "publisher": "jeremylongshore",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "coding"
    ],
    "tags": [
      "skill-md",
      "saas",
      "figma",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "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\"."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/jeremylongshore/tons-of-skills-marketplace",
      "path": "skills/.curated/figma-enterprise-rbac/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/jeremylongshore/tons-of-skills-marketplace/blob/HEAD/skills/.curated/figma-enterprise-rbac/SKILL.md",
      "key": "jeremylongshore/tons-of-skills-marketplace/skills/.curated/figma-enterprise-rbac/SKILL.md"
    },
    "compatibility": "Designed for Claude Code",
    "allowed_tools": [
      "Read,",
      "Write,",
      "Edit"
    ],
    "license": "MIT"
  },
  "instructions": "# Figma Enterprise RBAC\n\n## Overview\n\nFigma 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.\n\n## Prerequisites\n\n- Figma Enterprise or Organization plan\n- OAuth app registered in Figma developer dashboard\n- Understanding of OAuth 2.0 authorization code flow\n\n## Instructions\n\n### Step 1: OAuth 2.0 App Setup\n\n```typescript\n// Figma OAuth 2.0 Authorization Code Flow\n\n// 1. Build authorization URL\nfunction getAuthUrl(stat",
  "cost": {
    "context_tokens": 2196
  }
}

Fetch it by URL: GET /api/v1/registry/jeremylongshore-tons-of-skills-marketplace-figma-enterpr-ed741d/manifest?version=1.0.0

Reviews

Star ratings from people who tried it. One review per account; edit yours any time.

No reviews yet. Install it, try it, and be the first to rate it.