Skip to content
Skillv1.0.0

canva-enterprise-rbac

Configure Canva Enterprise organization access control and scope management. Use when implementing per-user scope control, managing Canva Enterprise features, or setting up organization-level Canva in

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 (plugins/saas-packs/canva-pack/skills/canva-enterprise-rbac/SKILL.md). Install upstream with npx skills add jeremylongshore/tons-of-skills-marketplace --skill canva-enterprise-rbac. Copyright stays with the author (MIT).

Canva Enterprise RBAC

Overview

Manage access control for Canva Connect API integrations at the organization level. The Canva API uses OAuth scopes (not roles) — your application layer implements RBAC on top of Canva's scope system.

Prerequisites

  • An external identity source, role/policy owner, protected mapping of subjects to approved tenants/assets/actions, and audit-retention policy.
  • Enterprise entitlement confirmation where a feature requires it; folder/team conventions alone are not authorization.

Instructions

  1. Authenticate and authorize every action in the application layer before invoking Canva; default-deny unknown roles, tenants, assets, and operations.
  2. Separate read, edit, export, publish, and delete approvals, and require elevated review for destructive or externally visible actions.
  3. Audit redacted allow/deny results and regularly test revocation; OAuth consent and Enterprise membership do not replace application authorization.

Canva Enterprise Requirements

Feature Canva Free/Pro Canva Enterprise
Design Create/Read Yes Yes
Export Designs Yes Yes
Asset Upload Yes Yes
Brand Templates No Yes
Autofill API No Yes
Folders (advanced) Limited Yes
Comments API Yes Yes

Key: Autofill and brand template APIs require the user to be a member of a Canva Enterprise organization.

Application-Level RBAC

// Your application controls what each user role can do with Canva

interface CanvaRole {
  name: string;
  scopes: string[];          // OAuth scopes to request
  allowedOperations: string[]; // Application-level operations
}

const CANVA_ROLES: Record<string, CanvaRole> = {
  viewer: {
    name: 'Viewer',
    scopes: ['design:meta:read'],
    allowedOperations: ['listDesigns', 'getDesign'],
  },
  creator: {
    name: 'Creator',
    scopes: ['design:meta:read', 'design:content:write', 'design:content:read', 'asset:write', 'asset:read'],
    allowedOperations: ['listDesigns', 'getDesign', 'createDesign', 'exportDesign', 'uploadAsset'],
  },
  admin: {
    name: 'Admin',
    scopes: [
      'design:meta:read', 'design:content:write', 'design:content:read',
      'asset:write', 'asset:read',
      'brandtemplate:meta:read', 'brandtemplate:content:read',
      'folder:read', 'folder:write',
      'comment:read', 'comment:write',
      'collaboration:event',
    ],
    allowedOperations: ['*'],
  },
};

// Request only the scopes needed for the user's role
function getScopesForRole(role: string): string[] {
  return CANVA_ROLES[role]?.scopes || CANVA_ROLES.viewer.scopes;
}

Permission Middleware

function requireCanvaOperation(operation: string) {
  return async (req: Request, res: Response, next: NextFunction) => {
    const userRole = req.user?.canvaRole || 'viewer';
    const role = CANVA_ROLES[userRole];

    if (!role) {
      return res.status(403).json({ error: 'Unknown role' });
    }

    if (!role.allowedOperations.includes('*') && !role.allowedOperations.includes(operation)) {
      return res.status(403).json({
        error: 'Forbidden',
        message: `Role '${userRole}' cannot perform '${operation}'`,
        requiredRole: Object.entries(CANVA_ROLES)
          .find(([, r]) => r.allowedOperations.includes(operation) || r.allowedOperations.includes('*'))
          ?.[0],
      });
    }

    next();
  };
}

// Usage
app.post('/api/designs',
  requireCanvaOperation('createDesign'),
  async (req, res) => {
    const result = await req.canva.createDesign(req.body);
    res.json(result);
  }
);

app.post('/api/autofill',
  requireCanvaOperation('autofillTemplate'),
  async (req, res) => {
    // Only admins can autofill — requires Enterprise + admin role
    const result = await req.canva.createAutofill(req.body);
    res.json(result);
  }
);

User Capabilities Check

// GET https://api.canva.com/rest/v1/users/me/capabilities
// Check what the authenticated user can do

async function checkUserCapabilities(token: string): Promise<{
  canAutofill: boolean;
  isEnterprise: boolean;
}> {
  try {
    const data = await canvaAPI('/users/me/capabilities', token);
    return {
      canAutofill: data.capabilities?.includes('autofill') || false,
      isEnterprise: data.capabilities?.includes('brand_template') || false,
    };
  } catch {
    return { canAutofill: false, isEnterprise: false };
  }
}

Scope-Based Access Control

// Track which scopes each user authorized
interface UserCanvaAuth {
  userId: string;
  grantedScopes: string[];   // Scopes the user consented to
  role: string;              // Application-assigned role
  connectedAt: Date;
}

// Check if a specific API call is authorized
function canPerformAction(
  userAuth: UserCanvaAuth,
  requiredScope: string
): boolean {
  // 1. Check application role allows the operation
  const role = CANVA_ROLES[userAuth.role];
  if (!role) return false;

  // 2. Check the required OAuth scope was granted by the user
  if (!userAuth.grantedScopes.includes(requiredScope)) {
    console.warn(`User ${userAuth.userId} missing scope: ${requiredScope}`);
    return false;
  }

  return true;
}

// If user needs additional scopes, redirect to re-authorize
function buildReAuthUrl(userId: string, additionalScopes: string[]): string {
  const existingScopes = userAuth.grantedScopes;
  const allScopes = [...new Set([...existingScopes, ...additionalScopes])];

  return getAuthorizationUrl({
    clientId: process.env.CANVA_CLIENT_ID!,
    redirectUri: process.env.CANVA_REDIRECT_URI!,
    scopes: allScopes,
    codeChallenge: generatePKCE().challenge,
    state: `reauth:${userId}`,
  });
}

Audit Logging

async function auditCanvaAction(entry: {
  userId: string;
  role: string;
  action: string;
  endpoint: string;
  success: boolean;
  designId?: string;
}): Promise<void> {
  await db.auditLog.insert({
    ...entry,
    service: 'canva-connect-api',
    timestamp: new Date(),
  });

  // Alert on permission escalation attempts
  if (!entry.success && entry.action === 'autofillTemplate') {
    console.warn(`Permission denied: user ${entry.userId} (role: ${entry.role}) attempted ${entry.action}`);
  }
}

Output

RBAC returns an allow/deny decision, policy version, opaque subject/scope IDs, and redacted audit event. It never treats a Canva scope, folder name, or team membership as sufficient proof of authorization by itself.

Examples

Before exporting a design, resolve the caller through the identity source, require an explicit export permission for the approved asset/tenant, and write an audit decision before creating the job. A user with broad OAuth consent still receives deny if the protected policy lacks the required export right.

Error Handling

Issue Cause Solution
403 on autofill Not Enterprise user Check user capabilities first
Scope not granted User rejected consent Show scope explanation, re-auth
Role mismatch Wrong role assigned Update user role in your DB
New scope needed Feature added Trigger re-authorization flow

Resources

Next Steps

For major migrations, see canva-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-canva-enterpr-872948/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-canva-enterpr-872948.ocm.jsonjson
{
  "ocm": "1",
  "id": "jeremylongshore-tons-of-skills-marketplace-canva-enterpr-872948",
  "kind": "skill",
  "name": "canva-enterprise-rbac",
  "description": "Configure Canva Enterprise organization access control and scope management. Use when implementing per-user scope control, managing Canva Enterprise features, or setting up organization-level Canva integration governance. Trigger with phrases like \"canva enterprise\", \"canva RBAC\", \"canva roles\", \"canva permissions\", \"canva organization\", \"canva team\".",
  "publisher": "jeremylongshore",
  "version": "1.0.0",
  "capabilities": {
    "domains": [
      "general"
    ],
    "tags": [
      "skill-md",
      "saas",
      "design",
      "canva",
      "skills-sh"
    ],
    "languages": [
      "en"
    ]
  },
  "quality_prior": 0.6,
  "examples": [
    "Configure Canva Enterprise organization access control and scope management. Use when implementing per-user scope control, managing Canva Enterprise features, or setting up organization-level Canva integration governance. Trigger with phrases like \"canva enterprise\", \"canva RBAC\", \"canva roles\", \"canva permissions\", \"canva organization\", \"canva team\"."
  ],
  "primary": false,
  "metadata": {
    "source": {
      "provider": "skills.sh",
      "repository": "https://github.com/jeremylongshore/tons-of-skills-marketplace",
      "path": "plugins/saas-packs/canva-pack/skills/canva-enterprise-rbac/SKILL.md",
      "ref": "HEAD",
      "url": "https://github.com/jeremylongshore/tons-of-skills-marketplace/blob/HEAD/plugins/saas-packs/canva-pack/skills/canva-enterprise-rbac/SKILL.md",
      "key": "jeremylongshore/tons-of-skills-marketplace/plugins/saas-packs/canva-pack/skills/canva-enterprise-rbac/SKILL.md"
    },
    "compatibility": "Designed for Claude Code",
    "allowed_tools": [
      "Read,",
      "Write,",
      "Edit"
    ],
    "license": "MIT"
  },
  "instructions": "# Canva Enterprise RBAC\n\n## Overview\n\nManage access control for Canva Connect API integrations at the organization level. The Canva API uses OAuth scopes (not roles) — your application layer implements RBAC on top of Canva's scope system.\n\n## Prerequisites\n\n- An external identity source, role/policy owner, protected mapping of subjects to approved tenants/assets/actions, and audit-retention policy.\n- Enterprise entitlement confirmation where a feature requires it; folder/team conventions alone are not authorization.\n\n## Instructions\n\n1. Authenticate and authorize every action in the applicatio",
  "cost": {
    "context_tokens": 1885
  }
}

Fetch it by URL: GET /api/v1/registry/jeremylongshore-tons-of-skills-marketplace-canva-enterpr-872948/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.