docs/docs/Develop/authorization.mdx
Langflow includes a pluggable authorization layer for role-based access control (RBAC) over flows, projects, deployments, files, variables, and knowledge bases.
The authorization infrastructure is present in all Langflow deployments, but the open-source build registers a pass-through service that always allows every action for every authenticated user.
Setting LANGFLOW_AUTHZ_ENABLED=true without an enforcement plugin does not restrict access. Route guards still run and audit rows can still be written, but no policy is applied.
Per-resource RBAC enforcement requires a registered authorization plugin. Langflow OSS does not include a registered authorization plugin.
The following steps apply when you have a registered enforcement plugin.
Set LANGFLOW_AUTHZ_AUDIT_ENABLED=true and run Langflow in a staging environment. Review the audit log to understand what decisions would be made before enforcement is on.
Install and register the enforcement plugin following its setup guide.
Set LANGFLOW_AUTHZ_ENABLED=true. The plugin reads the role and share tables and applies its policy.
Use the roles API and role assignments API to assign the built-in viewer, developer, or admin roles to your users, or create custom roles.
Use the shares API to grant cross-user access where needed.
| Variable | Description | Default |
|---|---|---|
LANGFLOW_AUTHZ_ENABLED | Enable authorization enforcement. Requires a registered enforcement plugin. When false, all requests pass regardless of roles or shares. | false |
LANGFLOW_AUTHZ_SUPERUSER_BYPASS | When true, active superusers bypass authorization checks. The plugin may still audit the decision. | true |
LANGFLOW_AUTHZ_AUDIT_ENABLED | Write an audit log row for every authorization decision and share-administration action. Works independently of LANGFLOW_AUTHZ_ENABLED — set this to true while enforcement is off to observe traffic before enabling enforcement. | false |
LANGFLOW_AUTHZ_AUDIT_DURABLE | Wait for each accepted audit row to commit. A full bounded queue applies backpressure and persistence failures fail the triggering request with a sanitized error. Enable this before treating the audit table as a compliance or external-delivery source. | false |
LANGFLOW_AUTHZ_AUDIT_RETENTION_DAYS | Number of days to retain audit log rows. Set to 0 to disable automatic pruning. | 90 |
LANGFLOW_AUTHZ_AUDIT_CLEANUP_INTERVAL | Seconds between retention sweep runs. A sweep also runs on startup. Minimum 300. | 86400 |
The default audit producer is intentionally best effort to preserve the OSS request-path behavior: a saturated queue or exhausted database flush can lose a row. Durable mode is explicit and fail-closed. It assigns the event ID and event time before enqueue, applies bounded backpressure, and acknowledges the caller only after the batch commits. Producer health reports only counters and bounded failure class names; database exception text is never exposed.
Langflow seeds three built-in system roles that an enforcement plugin uses as a starting point for policy sync. These roles cannot be deleted.
| Role | Permission slugs |
|---|---|
viewer | flow:read, project:read, deployment:read, file:read, variable:read, knowledge_base:read |
developer | viewer permissions plus flow:write, flow:execute, file:write, variable:write |
admin | All actions on all resource types |
You can create additional roles with the roles API. Role assignments take effect only after an enforcement plugin is registered.
All authorization endpoints are under /api/v1/authz/. Write operations require superuser privileges.
These endpoints manage the RBAC data model. An enforcement plugin consumes roles, assignments, and shares when evaluating requests. Without a plugin, API responses succeed but access is not restricted.
A share delegates an action on a resource; it does not delegate the owner's identity or credentials.
For an authenticated shared-flow run, the authenticated caller is the execution principal. Variables, files, nested flows, messages, jobs, and other dependencies resolve in that caller's namespace. A dependency must therefore be owned by the caller or shared with the caller separately. Langflow never falls back to the flow owner's credentials when a caller-owned or explicitly shared dependency is unavailable.
Only the flow owner can submit graph data or component-parameter tweaks. A non-owner receives the same not-found response as a caller without access so the rejection does not confirm that the flow exists.
Revoking a share prevents new runs and rechecked continuations, including HITL resume. It does not change the principal of work that is already running or terminate that work. Deployments and legacy public entry points are explicit exceptions:
auth_type=none) entry points execute with a stable, non-persisted anonymous principal under visitor-isolated session and storage namespaces. They never inherit the published flow owner's credentials, variables, files, or Memory Bases, and public requests cannot submit graph data or tweaks. Protected A2A (apikey or oauth) continues to require and execute as the flow owner.Owner-only execution retains detailed component errors for debugging. Delegated and public execution returns a stable generic workflow error without a component traceback or provider detail. Server logs and telemetry keep the original exception.
:::important Upgrade note: paused public A2A tasks
An A2A HITL resume requires the stored checkpoint's principal to match the principal the current request was admitted under. Checkpoints written before anonymous public execution existed recorded the flow owner, while an auth_type=none folder now admits the anonymous principal, so a public A2A task that is paused across this upgrade cannot be resumed and returns 404. There is no compatibility read for these rows on purpose: accepting an owner-principal checkpoint under an anonymous principal is exactly the protected-to-public transition this check exists to block. Drain or cancel paused public A2A tasks before upgrading, then start them again. Protected (apikey, oauth) A2A tasks are unaffected.
:::
The machine-validated endpoint-family contract is maintained in scripts/ci/execution_principal_matrix.json. Changes to a listed runtime surface must update that matrix and its referenced tests.
POST /api/v1/authz/me/permissions
Returns the allowed actions for a set of resources for the current user, without making individual resource requests that would trigger 403 responses. The frontend uses this to enable or disable UI controls when an enforcement plugin is active.
Request body:
| Field | Type | Description |
|---|---|---|
resource_type | string | One of: flow, deployment, project, knowledge_base, variable, file, component |
resource_ids | UUID[] | Resource IDs to evaluate. Maximum 500 per request. |
actions | string[] | Actions to check. Defaults to read, write, execute, delete, create. Maximum 10. |
domain | string | Authorization domain. Typically project:{folder_id} or *. Defaults to *. |
Response:
{
"resource_type": "flow",
"permissions": {
"3fa85f64-5717-4562-b3fc-2c963f66afa6": ["read", "execute"]
}
}
/api/v1/authz/shares
Shares grant access to a resource across user boundaries. The resource owner or a superuser can administer shares for their own resources.
| Method | Path | Description |
|---|---|---|
POST | /api/v1/authz/shares | Create a share |
GET | /api/v1/authz/shares | List shares visible to the current user |
GET | /api/v1/authz/shares/{share_id} | Get a specific share |
PATCH | /api/v1/authz/shares/{share_id} | Update a share |
DELETE | /api/v1/authz/shares/{share_id} | Delete a share |
Each share write fires an invalidation call to the authorization plugin so cached policy is refreshed.
/api/v1/authz/roles — superuser only for writes
| Method | Path | Description |
|---|---|---|
GET | /api/v1/authz/roles | List roles. Filter by is_system or name substring. |
GET | /api/v1/authz/roles/{role_id} | Get a specific role |
POST | /api/v1/authz/roles | Create a custom role |
PATCH | /api/v1/authz/roles/{role_id} | Update a role name, description, or permissions |
DELETE | /api/v1/authz/roles/{role_id} | Delete a custom role (system roles cannot be deleted) |
/api/v1/authz/role-assignments — superuser only for writes
| Method | Path | Description |
|---|---|---|
GET | /api/v1/authz/role-assignments | List role assignments |
POST | /api/v1/authz/role-assignments | Assign a role to a user |
DELETE | /api/v1/authz/role-assignments/{assignment_id} | Remove a role assignment |
/api/v1/authz/teams — superuser only for writes
| Method | Path | Description |
|---|---|---|
GET | /api/v1/authz/teams | List teams |
GET | /api/v1/authz/teams/{team_id} | Get a specific team |
POST | /api/v1/authz/teams | Create a team |
PATCH | /api/v1/authz/teams/{team_id} | Update a team |
DELETE | /api/v1/authz/teams/{team_id} | Delete a team |
GET | /api/v1/authz/teams/{team_id}/members | List team members |
POST | /api/v1/authz/teams/{team_id}/members | Add a member to a team |
DELETE | /api/v1/authz/teams/{team_id}/members/{user_id} | Remove a member from a team |
GET /api/v1/authz/audit — superuser only
Returns a paginated, filterable view of the authorization audit log.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
user_id | UUID | Filter by acting user |
resource_type | string | Filter by resource type slug (for example, flow) |
resource_id | UUID | Filter by resource UUID |
action | string | Filter by action string (for example, flow:read or share:create) |
result | string | Filter by decision: allow, deny, or owner_override |
since | datetime | Inclusive lower bound on timestamp |
until | datetime | Exclusive upper bound on timestamp |
Page size is capped at 200 rows.