Claude-code-plugins-plus langfuse-enterprise-rbac

install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/langfuse-pack/skills/langfuse-enterprise-rbac" ~/.claude/skills/jeremylongshore-claude-code-plugins-plus-langfuse-enterprise-rbac && rm -rf "$T"
manifest: plugins/saas-packs/langfuse-pack/skills/langfuse-enterprise-rbac/SKILL.md
source content

Langfuse Enterprise RBAC

Overview

Configure enterprise access control for Langfuse: built-in roles and permissions, scoped API keys per service, SSO integration, project-level isolation, and audit logging for compliance.

Prerequisites

  • Langfuse Cloud (Team/Enterprise plan) or self-hosted instance
  • Organization admin access
  • SSO provider (optional, for SAML/OIDC integration)

Langfuse Built-In Roles

Langfuse provides these roles at the project level:

RoleView TracesCreate TracesManage PromptsManage MembersManage Billing
OwnerYesYesYesYesYes
AdminYesYesYesYesNo
MemberYesYesYesNoNo
ViewerYesNoNoNoNo

Instructions

Step 1: Organization and Project Structure

Organization: Acme Corp
├── Project: production-chatbot
│   ├── Owner: engineering-lead@acme.com
│   ├── Admin: senior-dev@acme.com
│   ├── Member: developer@acme.com
│   └── API Key: sk-lf-prod-chatbot-...
│
├── Project: staging-chatbot
│   ├── Admin: senior-dev@acme.com
│   ├── Member: developer@acme.com
│   └── API Key: sk-lf-staging-chatbot-...
│
└── Project: analytics-readonly
    ├── Admin: data-lead@acme.com
    ├── Viewer: analyst@acme.com
    └── API Key: sk-lf-analytics-...

Best practice: Separate projects for production, staging, and analytics. Never share API keys across environments.

Step 2: Scoped API Keys

Create API keys with specific purposes and rotate regularly:

// In Langfuse UI: Settings > API Keys > Create
// Each key pair (public + secret) is scoped to one project

// Service-specific keys
// Backend API:     pk-lf-prod-api-...  / sk-lf-prod-api-...
// CI/CD pipeline:  pk-lf-ci-...       / sk-lf-ci-...
// Analytics:       pk-lf-analytics-... / sk-lf-analytics-...

// Validate key scope at startup
function validateApiKeyScope(expectedProject: string) {
  const pk = process.env.LANGFUSE_PUBLIC_KEY || "";

  if (!pk.includes(expectedProject)) {
    console.warn(
      `WARNING: API key may not match expected project: ${expectedProject}`
    );
  }
}

// Key rotation script
async function rotateApiKeys() {
  // 1. Create new key pair in Langfuse UI
  // 2. Deploy new keys to secret manager
  // 3. Wait for all instances to pick up new keys
  // 4. Revoke old key pair in Langfuse UI

  console.log("Key rotation checklist:");
  console.log("1. [ ] New key pair created in Langfuse");
  console.log("2. [ ] New keys deployed to secret manager");
  console.log("3. [ ] All services restarted with new keys");
  console.log("4. [ ] Old key pair revoked in Langfuse");
  console.log("5. [ ] Verified traces flowing with new keys");
}

Step 3: Self-Hosted Access Control

# docker-compose.yml -- enterprise hardening
services:
  langfuse:
    image: langfuse/langfuse:latest
    environment:
      # Disable public registration
      - AUTH_DISABLE_SIGNUP=true

      # SSO enforcement for your domain
      - AUTH_DOMAINS_WITH_SSO_ENFORCEMENT=acme.com

      # Default role for new project members
      - LANGFUSE_DEFAULT_PROJECT_ROLE=VIEWER

      # Encrypt data at rest
      - ENCRYPTION_KEY=${ENCRYPTION_KEY}

      # Session security
      - NEXTAUTH_SECRET=${NEXTAUTH_SECRET}

Step 4: SSO Integration

SAML Setup (Okta, Azure AD, OneLogin):

  1. In your IdP, create a new SAML application for Langfuse
  2. Configure the SSO callback URL:
    https://langfuse.your-domain.com/api/auth/callback/saml
  3. Set the entity ID:
    https://langfuse.your-domain.com
  4. Map IdP groups to Langfuse roles:
# Self-hosted SSO configuration
services:
  langfuse:
    environment:
      - AUTH_CUSTOM_CLIENT_ID=${SAML_CLIENT_ID}
      - AUTH_CUSTOM_CLIENT_SECRET=${SAML_CLIENT_SECRET}
      - AUTH_CUSTOM_ISSUER=https://your-idp.com/saml
      - AUTH_DOMAINS_WITH_SSO_ENFORCEMENT=acme.com

Step 5: Audit Logging

Track access and permission changes for compliance:

// Application-level audit logging for Langfuse operations
import { LangfuseClient } from "@langfuse/client";

interface AuditEvent {
  timestamp: string;
  actor: string;
  action: string;
  resource: string;
  details: Record<string, any>;
}

const auditLog: AuditEvent[] = [];

function logAuditEvent(event: Omit<AuditEvent, "timestamp">) {
  const entry: AuditEvent = {
    ...event,
    timestamp: new Date().toISOString(),
  };
  auditLog.push(entry);
  console.log(`[AUDIT] ${entry.action}: ${entry.resource} by ${entry.actor}`);

  // In production: send to your SIEM or audit log service
  // await sendToSIEM(entry);
}

// Audit Langfuse API key usage
function auditedLangfuseClient(actor: string): LangfuseClient {
  const client = new LangfuseClient();

  // Log score creation
  const originalScoreCreate = client.score.create.bind(client.score);
  client.score.create = async (params) => {
    logAuditEvent({
      actor,
      action: "score.create",
      resource: `trace:${params.traceId}`,
      details: { scoreName: params.name },
    });
    return originalScoreCreate(params);
  };

  return client;
}

Access Control Checklist

CategoryRequirementImplementation
AuthenticationSSO enforced for org domain
AUTH_DOMAINS_WITH_SSO_ENFORCEMENT
RegistrationPublic signup disabled
AUTH_DISABLE_SIGNUP=true
Default roleLeast privilege
LANGFUSE_DEFAULT_PROJECT_ROLE=VIEWER
API keysPer-service, per-environmentSeparate keys in secret manager
Key rotationQuarterly or on compromiseDocumented rotation procedure
Data encryptionAt-rest encryption
ENCRYPTION_KEY
configured
Audit trailAll access loggedApplication-level audit logging

Error Handling

IssueCauseSolution
Permission deniedInsufficient roleRequest role upgrade from project owner
SSO login failsWrong callback URLVerify SAML callback URL matches
API key rejectedWrong project or revokedCreate new key pair for correct project
New user gets no accessNot added to projectAdmin must invite to specific project

Resources