Cognee Permissions System
The Cognee permission system manages access to data through an access control architecture. This system provides data isolation and access control through dataset-scoped permissions and per-dataset storage, enabling multiple users or organizations to use the same Cognee instance while keeping their data completely separate.Enable Backend Access Control (EBAC) is the configuration flag that activates this multi-tenant mode, enforcing user authentication and complete data isolation.
Core Components
The permission system is built around several key concepts:- Dataset — The basic unit of data in Cognee. All documents and their processed knowledge graphs belong to a dataset. Permissions are always defined at the dataset level. See Datasets for details.
- Principal — Any entity that can hold permissions. Principals come in three forms: Users, Tenants, and Roles. This unified design supports flexible access control across individuals and organizations.
- User — An individual who creates and interacts with datasets. Users can own datasets and be granted permissions on others. A user can belong to several tenants but acts inside one active tenant at a time, which scopes every dataset lookup. See Tenants.
- Tenant — An organization or group. Tenants contain users and can be granted permissions on datasets, which apply to all members.
- Role — A group of users within a tenant. Roles can also be granted dataset permissions, which apply to their members.
- ACL — The Access Control List records all permission assignments. Each entry links a principal to a dataset with a specific permission type. See ACL for details.
Permission Types
There are four types of permissions that can be granted on datasets:- Read — View documents and query stored memory
- Write — Remember data, improve datasets, or otherwise modify stored memory
- Delete — Remove datasets or dataset-scoped memory
- Share — Grant permissions to other principals
delete permission on the target dataset. If a user lacks delete, the API returns a not-found or unauthorized response depending on the endpoint and auth mode.
Capabilities
The four permission types above are always about one dataset. Capabilities are the second authorization axis: tenant-scoped actions that are not about any dataset at all, such as administering a tenant’s members. They live in their ownprincipal_capabilities table, keyed on (principal, tenant, capability), so a capability name never sits next to read/write/delete/share and the two axes cannot be confused for one another.
The catalog is system-defined and closed — the code is what gives each name meaning, so you assign capabilities but cannot invent them:
Granting and revoking are deliberately separate from
manage_users, and neither comes with it: deciding who may do what in a tenant is a different job from adding and removing its members.
Capability Resolution
A user’s capabilities in a tenant are the union of everything granted at three levels, exactly as dataset permissions are:- Tenant grants — reach every current and future member of the tenant
- Role grants — reach the members of that role
- Direct user grants — reach that one person, in that one tenant
- The tenant owner holds the entire catalog, without any row being stored for them. A capability later added to the catalog reaches them without a grant, and they cannot be revoked out of their own tenant.
- Resolution is gated on actual tenant membership. A grant written for someone before they join the tenant resolves to nothing until they are a member — and granting to a user who is not a member is refused outright, with a message saying to add them to the tenant first.
- The catalog is authoritative at read time. A stored name that is no longer in the catalog stops resolving, so shrinking the catalog cannot leave stale grants in force.
admin role-name fallback is what carries such a tenant until its capabilities are assigned explicitly.
Granting and Revoking
One pair of endpoints serves all three principal types, because a capability row is(principal, tenant, capability) regardless of what the principal is:
POST /api/v1/permissions/capabilities/{principal_id}— grantDELETE /api/v1/permissions/capabilities/{principal_id}— revoke
capability query parameter (?capability=manage_users&capability=grant_capabilities) and an optional tenant_id, which defaults to the caller’s current tenant and is ignored when the principal is a role or a tenant, since those carry their own. A batch is all or nothing — one unrecognized name rejects the whole request with 400 and nothing is written — and both operations are idempotent, so a retry is safe.
The caller needs grant_capabilities (or revoke_capabilities) in the target tenant, and granting only passes on what the caller already holds: grant_capabilities is not a path to the rest of the catalog. Revoking can take any capability away, and a member keeps a capability if another level still grants it, since resolution is a union. Each new grant records who made it.
403 is returned for a caller without grant_capabilities (or revoke_capabilities) in the target tenant, a principal that does not exist, and a tenant that does not exist alike — the responses are deliberately indistinguishable, so the endpoints cannot be used to probe which ids are real.
To read your own capabilities in a tenant, use GET /api/v1/permissions/tenants/{tenant_id}/capabilities/me.
How It Works
WhenENABLE_BACKEND_ACCESS_CONTROL is set to true, Cognee runs in access control mode:
- Authentication becomes mandatory (even if
REQUIRE_AUTHENTICATION=false) - Data isolation is enforced at the user + dataset level for graph and vector stores
- Database routing is automatic — Databases are configured per request via context variables through the Dataset Database Handler Mechanism
- Vector handler routing stays automatic — When access control is enabled, Cognee routes vector storage through a dataset database handler. Built-in providers such as
pgvectorandtursoauto-select their matching handler when you leaveVECTOR_DATASET_DATABASE_HANDLERat its default value; explicitly setting an incompatible handler still causes 401/403 errors. See Permissions Setup for supported combinations.
Permission Resolution
When a user tries to access data, the system evaluates their effective permissions by combining:- Direct user permissions — explicitly granted to the user
- Role permissions — inherited through the user’s role memberships
- Tenant permissions — inherited through the user’s tenant membership
principal_capabilities table rather than the ACL, and scoped to a tenant rather than a dataset.
Data Storage Layout
When EBAC is enabled, Cognee automatically organizes data by user and dataset for file based databases like LanceDB and Kuzu: Filesystem layout:- Each user gets their own database directory
- Each dataset gets its own database files within the user’s directory
Datasets
Learn about datasets as the core unit of data
Setup Configuration
Configure multi-tenant mode and access control