LI

linear-enterprise-rbac

Manage Linear security permissions, SSO, and SCIM provisioning for enterprise compliance.

Install

mkdir -p .claude/skills/linear-enterprise-rbac && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/4693" && unzip -o skill.zip -d .claude/skills/linear-enterprise-rbac && rm skill.zip

Installs to .claude/skills/linear-enterprise-rbac

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Implement enterprise role-based access control with Linear.
59 charsno explicit “when” trigger
Advanced

Key capabilities

  • Implement role-based access control for integrations
  • Map application roles to Linear OAuth scopes
  • Configure SAML SSO for enterprise access
  • Provision users via SCIM
  • Audit user permission levels and actions

How it works

The skill provides patterns for mapping application-level roles to Linear OAuth scopes and configuring enterprise security features like SAML and SCIM.

Inputs & outputs

You give it
User role and permission request
You get back
Access validation or restriction

When to use linear-enterprise-rbac

  • Configure team-based access control
  • Map user roles to OAuth scopes
  • Implement SAML SSO settings
  • Audit user permission levels

About this skill

Linear Enterprise RBAC

Overview

Implement role-based access control for Linear integrations. Linear provides built-in organization roles (Owner, Admin, Member, Guest), team-level access control, and fine-grained OAuth scopes. Enterprise plans add SAML 2.0 SSO and SCIM user provisioning.

Prerequisites

  • Linear Business or Enterprise plan (for SSO/SCIM)
  • Organization admin access
  • SSO provider (Okta, Azure AD, Google Workspace) for SAML
  • Understanding of OAuth 2.0 scopes

Instructions

Step 1: Understand Linear's Built-In Roles

RoleCapabilities
OwnerFull workspace control, billing, delete workspace
AdminManage members, teams, integrations, workspace settings
MemberCreate/edit issues, access team-visible data
GuestRead-only access to invited teams only

These roles are fixed in Linear. Your application can layer additional permissions on top.

Step 2: Map Application Roles to OAuth Scopes

// src/auth/permissions.ts

// Available Linear OAuth scopes:
// read, write, issues:create, admin
// initiative:read, initiative:write
// customer:read, customer:write

const ROLE_SCOPES: Record<string, string[]> = {
  admin: ["read", "write", "issues:create", "admin"],
  manager: ["read", "write", "issues:create"],
  developer: ["read", "write", "issues:create"],
  viewer: ["read"],
};

const TEAM_ACCESS: Record<string, "member" | "guest" | "none"> = {
  admin: "member",
  manager: "member",
  developer: "member",
  viewer: "guest",
};

Step 3: Permission Guard

import { LinearClient } from "@linear/sdk";

interface UserContext {
  userId: string;
  role: string;
  linearClient: LinearClient;
  teamIds: string[];
}

class PermissionGuard {
  constructor(private ctx: UserContext) {}

  canAccessTeam(teamId: string): boolean {
    if (this.ctx.role === "admin") return true;
    return this.ctx.teamIds.includes(teamId);
  }

  async canModifyIssue(issueId: string): Promise<boolean> {
    if (this.ctx.role === "viewer") return false;

    const issue = await this.ctx.linearClient.issue(issueId);
    const team = await issue.team;
    return team ? this.canAccessTeam(team.id) : false;
  }

  canCreateIssue(): boolean {
    return ["admin", "manager", "developer"].includes(this.ctx.role);
  }

  canDeleteIssue(): boolean {
    return this.ctx.role === "admin";
  }

  canManageIntegration(): boolean {
    return this.ctx.role === "admin";
  }

  canAccessProject(projectTeamIds: string[]): boolean {
    if (this.ctx.role === "admin") return true;
    return projectTeamIds.some(id => this.ctx.teamIds.includes(id));
  }
}

// Express middleware
function requireRole(...allowedRoles: string[]) {
  return (req: any, res: any, next: any) => {
    if (!allowedRoles.includes(req.user.role)) {
      return res.status(403).json({ error: "Insufficient role" });
    }
    next();
  };
}

// Route protection
app.post("/api/issues", requireRole("admin", "manager", "developer"), createIssueHandler);
app.delete("/api/issues/:id", requireRole("admin"), deleteIssueHandler);
app.get("/api/issues", requireRole("admin", "manager", "developer", "viewer"), listIssuesHandler);

Step 4: Scoped Client Factory

// Create Linear clients with appropriate access per user
async function getClientForUser(userId: string): Promise<LinearClient> {
  const token = await getStoredOAuthToken(userId);
  if (!token) throw new Error("User not authenticated with Linear");
  return new LinearClient({ accessToken: token });
}

// Verify team membership via API
async function getUserTeamIds(client: LinearClient): Promise<string[]> {
  const viewer = await client.viewer;
  const memberships = await viewer.teamMemberships();

  const teamIds: string[] = [];
  for (const membership of memberships.nodes) {
    const team = await membership.team;
    if (team) teamIds.push(team.id);
  }
  return teamIds;
}

Step 5: SAML SSO Configuration (Enterprise)

// Linear Enterprise supports SAML 2.0 SSO
// Configuration: Linear Settings > Security > SAML

// After SSO login, verify user's Linear access
async function onSSOLogin(email: string): Promise<UserContext> {
  // Look up user's stored OAuth token
  const user = await db.users.findByEmail(email);
  if (!user?.linearAccessToken) {
    throw new Error("User must complete Linear OAuth after SSO login");
  }

  const client = new LinearClient({ accessToken: user.linearAccessToken });
  const viewer = await client.viewer;
  const teamIds = await getUserTeamIds(client);

  return {
    userId: user.id,
    role: mapLinearRoleToAppRole(viewer),
    linearClient: client,
    teamIds,
  };
}

function mapLinearRoleToAppRole(viewer: any): string {
  if (viewer.admin) return "admin";
  if (viewer.guest) return "viewer";
  return "developer";
}

Step 6: SCIM Provisioning (Enterprise)

// SCIM auto-syncs users and groups from your IdP to Linear
// Configuration: Linear Settings > Security > SCIM provisioning
// Endpoint: https://api.linear.app/scim/v2
// Bearer token: generated in Linear admin settings

// After SCIM syncs users, verify in your app
async function syncSCIMUsers(client: LinearClient) {
  const org = await client.organization;
  const members = await org.users();

  for (const user of members.nodes) {
    console.log(`${user.name} (${user.email}): admin=${user.admin}, guest=${user.guest}, active=${user.active}`);

    // Sync to your app's user database
    await db.users.upsert({
      email: user.email,
      name: user.name,
      linearId: user.id,
      role: user.admin ? "admin" : user.guest ? "viewer" : "developer",
      active: user.active,
    });
  }
}

Step 7: Audit Logging

interface AuditEntry {
  timestamp: string;
  userId: string;
  action: string;
  resource: string;
  resourceId: string;
  details: Record<string, unknown>;
}

function logAudit(entry: AuditEntry): void {
  // Write to audit log (database, SIEM, CloudWatch, etc.)
  console.log(JSON.stringify(entry));
}

// Wrap Linear operations with audit logging
async function auditedCreateIssue(
  ctx: UserContext,
  input: { teamId: string; title: string; [key: string]: any }
) {
  const guard = new PermissionGuard(ctx);
  if (!guard.canCreateIssue()) throw new Error("Forbidden");
  if (!guard.canAccessTeam(input.teamId)) throw new Error("No team access");

  const result = await ctx.linearClient.createIssue(input);

  logAudit({
    timestamp: new Date().toISOString(),
    userId: ctx.userId,
    action: "issue.create",
    resource: "Issue",
    resourceId: (await result.issue)?.id ?? "",
    details: { teamId: input.teamId, title: input.title },
  });

  return result;
}

async function auditedUpdateIssue(
  ctx: UserContext,
  issueId: string,
  updates: Record<string, unknown>
) {
  const guard = new PermissionGuard(ctx);
  if (!(await guard.canModifyIssue(issueId))) throw new Error("Forbidden");

  logAudit({
    timestamp: new Date().toISOString(),
    userId: ctx.userId,
    action: "issue.update",
    resource: "Issue",
    resourceId: issueId,
    details: updates,
  });

  return ctx.linearClient.updateIssue(issueId, updates);
}

Error Handling

ErrorCauseSolution
ForbiddenToken lacks required scopeRequest OAuth with correct ROLE_SCOPES
Authentication requiredSSO session expiredRedirect to SAML IdP
SCIM sync failsInvalid bearer tokenRegenerate SCIM token in Linear admin
Guest can't create issueGuest role is read-onlyUpgrade to Member role in Linear
Team not accessibleUser not added to teamAdd user to team in Linear Settings

Examples

List Organization Members by Role

const client = new LinearClient({ apiKey: process.env.LINEAR_API_KEY! });
const org = await client.organization;
const members = await org.users();

for (const user of members.nodes) {
  const role = user.admin ? "admin" : user.guest ? "guest" : "member";
  console.log(`${user.name} (${user.email}): ${role}`);
}

Resources

When not to use it

  • When using a plan below Business or Enterprise for SSO/SCIM
  • When user lacks admin access for configuration

Prerequisites

Linear Business or Enterprise planOrganization admin accessSSO provider for SAML

Limitations

  • Guest role is read-only
  • Requires Business or Enterprise plan for SSO/SCIM

How it compares

It enables programmatic enforcement of enterprise-grade access control and auditing rather than relying solely on manual UI settings.

Compared to similar skills

linear-enterprise-rbac side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
linear-enterprise-rbac (this skill)127dReviewAdvanced
1password272moReviewIntermediate
security-compliance197moReviewAdvanced
information-security-manager-iso27001117moReviewAdvanced

Try saying

Example prompts that trigger this skill in your AI assistant.

More by jeremylongshore

View all by jeremylongshore

analyzing-logs

jeremylongshore

Analyze application logs to detect performance issues, identify error patterns, and improve stability by extracting key insights.

14123

ollama-setup

jeremylongshore

Configure auto-configure Ollama when user needs local LLM deployment, free AI alternatives, or wants to eliminate hosted API costs. Trigger phrases: "install ollama", "local AI", "free LLM", "self-hosted AI", "replace OpenAI", "no API costs". Use when appropriate context detected. Trigger with relevant phrases based on skill purpose.

1167

backtesting-trading-strategies

jeremylongshore

Backtest crypto and traditional trading strategies against historical data. Calculates performance metrics (Sharpe, Sortino, max drawdown), generates equity curves, and optimizes strategy parameters. Use when user wants to test a trading strategy, validate signals, or compare approaches. Trigger with phrases like "backtest strategy", "test trading strategy", "historical performance", "simulate trades", "optimize parameters", or "validate signals".

1071

generating-database-seed-data

jeremylongshore

Process this skill enables AI assistant to generate realistic test data and database seed scripts for development and testing environments. it uses faker libraries to create realistic data, maintains relational integrity, and allows configurable data volumes. u... Use when working with databases or data models. Trigger with phrases like 'database', 'query', or 'schema'.

1033

cursor-codebase-indexing

jeremylongshore

Execute set up and optimize Cursor codebase indexing. Triggers on "cursor index setup", "codebase indexing", "index codebase", "cursor semantic search". Use when working with cursor codebase indexing functionality. Trigger with phrases like "cursor codebase indexing", "cursor indexing", "cursor".

885

testing-mobile-apps

jeremylongshore

Execute mobile app testing on iOS and Android devices/simulators. Use when performing specialized testing. Trigger with phrases like "test mobile app", "run iOS tests", or "validate Android functionality".

810

You might also like

1password

openclaw

Set up and use 1Password CLI (op). Use when installing the CLI, enabling desktop app integration, signing in (single or multi-account), or reading/injecting/running secrets via op.

2799

security-compliance

davila7

Guides security professionals in implementing defense-in-depth security architectures, achieving compliance with industry frameworks (SOC2, ISO27001, GDPR, HIPAA), conducting threat modeling and risk assessments, managing security operations and incident response, and embedding security throughout the SDLC.

1981

information-security-manager-iso27001

davila7

Senior Information Security Manager specializing in ISO 27001 and ISO 27002 implementation for HealthTech and MedTech companies. Provides ISMS implementation, cybersecurity risk assessment, security controls management, and compliance oversight. Use for ISMS design, security risk assessments, control implementation, and ISO 27001 certification activities.

1169

cursor-sso-integration

jeremylongshore

Configure SSO and enterprise authentication in Cursor. Triggers on "cursor sso", "cursor saml", "cursor oauth", "enterprise cursor auth", "cursor okta". Use when working with cursor sso integration functionality. Trigger with phrases like "cursor sso integration", "cursor integration", "cursor".

433

springboot-security

affaan-m

Spring Security best practices for authn/authz, validation, CSRF, secrets, headers, rate limiting, and dependency security in Java Spring Boot services.

529

django-security

affaan-m

Django security best practices, authentication, authorization, CSRF protection, SQL injection prevention, XSS prevention, and secure deployment configurations.

522

Search skills

Search the agent skills registry