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.
Langfuse provides these roles at the project level:
| Role | View Traces | Create Traces | Manage Prompts | Manage Members | Manage Billing |
|---|---|---|---|---|---|
| Owner | Yes | Yes | Yes | Yes | Yes |
| Admin | Yes | Yes | Yes | Yes | No |
| Member | Yes | Yes | Yes | No | No |
| Viewer | Yes | No | No | No | No |
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.
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");
}
# 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}
SAML Setup (Okta, Azure AD, OneLogin):
https://langfuse.your-domain.com/api/auth/callback/saml
https://langfuse.your-domain.com
# 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
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;
}
| Category | Requirement | Implementation |
|---|---|---|
| Authentication | SSO enforced for org domain | AUTH_DOMAINS_WITH_SSO_ENFORCEMENT |
| Registration | Public signup disabled | AUTH_DISABLE_SIGNUP=true |
| Default role | Least privilege | LANGFUSE_DEFAULT_PROJECT_ROLE=VIEWER |
| API keys | Per-service, per-environment | Separate keys in secret manager |
| Key rotation | Quarterly or on compromise | Documented rotation procedure |
| Data encryption | At-rest encryption | ENCRYPTION_KEY configured |
| Audit trail | All access logged | Application-level audit logging |
| Issue | Cause | Solution |
|---|---|---|
| Permission denied | Insufficient role | Request role upgrade from project owner |
| SSO login fails | Wrong callback URL | Verify SAML callback URL matches |
| API key rejected | Wrong project or revoked | Create new key pair for correct project |
| New user gets no access | Not added to project | Admin must invite to specific project |