Skip to content

Knowledge base access control ​

A knowledge base can decide who reads each of its documents. This page covers switching access control on, folders, permissions, external directories, and how the rest of the console treats work that used restricted documents. The base Knowledge Engine is described in Knowledge Engine.

Access control is off by default and switched on per knowledge base. A knowledge base that leaves it off works as before: everyone who can read the knowledge base reads every document in it.

PATCH /api/client/v1/rag/modules/:key
Authorization: Bearer <token>
json
{ "access": { "enabled": true } }

Changing access needs Knowledge Engine admin. Switching access control on hides nothing by itself: the top level of the knowledge base stays open to everyone until its permissions are changed. Switching it off again keeps every permission and applies none until it is switched back on. A source of the Connectors module (Enterprise) that sends the permissions of its files goes on adding documents, with their permissions kept and not applied, and the connector's list of sources marks it Permissions not applied: access control is off.

How permissions apply ​

Permissions sit on the knowledge base itself (its top level), on a folder or on a document. A folder or a document uses the permissions of the folder it is in, and so on up to the top level, unless it has its own (mode: "own"), which replace what it would inherit.

  • The top level without entries is open to everyone who can read the knowledge base.
  • A folder or a document with its own permissions and no entries is read by nobody, apart from the exception for administrators below.
  • A document in a folder that no longer exists is read by nobody, apart from that exception.

An entry names who may read:

PrincipalWho
everyoneEveryone who can read the knowledge base
user:<id>A console user
group:<id>A console group
token:<id>An API token, for calls with no person behind them
email:<address>The console person with this e-mail address
x:<directory>:u:<id>A user of an external directory
x:<directory>:g:<id>A group of an external directory
x:<directory>:allEvery member of an external directory, not its guests

A folder or a document holds at most 1000 entries. An entry may carry a label of up to 200 characters, which is shown and never used to decide. The users, groups, tokens and directories an entry names must exist (400 principal_unknown).

Who reads what ​

CallerReads
A person: a session, a run they started, a call that acts for themWhat their user, e-mail address, groups and matched directory identities are named on
An API token with no person behind itWhat is open to everyone, and what names the token
No person: a trigger, the agent steps of a flowWhat is open to everyone
Ingest, re-indexing, connector syncsEvery document

A flow runs as its owner, but no person is asking, so its agent steps and the tools they call read as no one in particular. The flow editor's playground reads as the person at the screen. A reminder an agent sets wakes reading no more than the turn that set it: one set by an agent step of a flow, in a shared channel, or in a paused turn that someone else continued reads as no one.

The people who administer a knowledge base (Knowledge Engine admin in its project) read every document in searches, answers, agent tools and document reads, unless the knowledge base turns that off with "adminBypass": false. In the management views (document lists, folders, permissions) they always see every document, so they can set permissions. Calls of the client API never get this exception.

Reads are checked on every path: queries and searches, answers, the client API, agent knowledge tools, the knowledge base MCP tools, and document detail, content, lines and export. The check happens while the vector store is searched, before a reranker or the score threshold sees a passage. A document the caller may not read is left out of lists and answers 404, like a missing one. A knowledge base with access control is listed without totalDocuments and totalChunks for a caller whose reads are checked (an API token always is).

Folders ​

Folders form a tree in each knowledge base, with access control on or off. An ingest or a re-ingest can place a document with folderId, or with a folderPath such as Finance/Budgets whose missing folders are created. The dashboard routes (session authentication, in the active project) manage folders:

RouteDoes
GET /api/rag/modules/:key/foldersLists the folders, each with the number of documents directly in it, counted as the caller's document list shows them. A folder the caller sees only on the way to one they may read is marked pathOnly and shows documents: 0
POST /api/rag/modules/:key/foldersCreates one: { "name": "Budgets", "parentId": "<folder id>" } (parentId: null: the top level)
PATCH /api/rag/modules/:key/folders/:folderIdRenames it (name) or moves it (parentId)
DELETE /api/rag/modules/:key/folders/:folderIdDeletes it, when it holds no folder and no document (409 folder_not_empty)
POST /api/rag/modules/:key/documents/moveMoves up to 500 documents: { "documentIds": ["..."], "folderId": "<folder id>" }
PATCH /api/rag/modules/:key/documents/:documentIdMoves one document: { "folderId": null } puts it at the top level

They need Knowledge Engine write. With access control on, only the administrators of the knowledge base, and an API token with Knowledge Engine admin, create, change and delete folders and move documents (403 access_denied). Anyone else lists only the folders they may read and the folders above them, and their ingest places a new document only in a folder they can read, without creating one. A folder name has 1 to 200 characters, with no / and no control characters. Folders nest at most 64 levels (400 folder_too_deep), two folders under one parent cannot share a name (409 folder_exists), and a folder cannot move below itself (409 folder_cycle).

Setting permissions ​

GET /api/rag/modules/:key/acl?node=folder:<folder id>
PUT /api/rag/modules/:key/acl
json
{
  "node": "folder:65f0c2a1e4b0a1b2c3d4e5f6",
  "mode": "own",
  "entries": [
    { "principal": "group:65f0c2a1e4b0a1b2c3d4e5f7", "label": "Finance" },
    "email:ada@example.com"
  ]
}

node is module (the default, the top level), folder:<id> or document:<id>. mode: "inherit" drops the own permissions of a folder or a document; the top level always has its own. The answer holds the node's own entries and the effective ones, those of the nearest node with its own, with openToEveryone: true when that is the top level without entries. Both routes need Knowledge Engine admin. An ingest or a re-ingest can set a document's own permissions with acl ({ "mode": "own", "entries": [...] }), which needs admin too.

To check one person, GET /api/rag/modules/:key/access/explain?userId=<id>&documentId=<id> answers whether a console user of the project can read the document (readable), which node decides (effectiveNode), and which of the person's keys its entries name (grantedBy). Knowledge Engine admins of the whole workspace also see who the person is: their e-mail address, groups, every key and how the directories matched them.

Views of the Access tab ​

The console's Access tab reads these dashboard routes. All need Knowledge Engine admin in the project, and answer 404 module_not_found for a knowledge base that is not in it.

RouteDoes
GET /api/rag/modules/:key/access/summaryThe state of the knowledge base: enabled, adminBypass, whether the top level is open to everyone (root), how many folders and documents are total, have their own permissions, come from a source (synced) or are closed, and the directories the permissions name
POST /api/rag/modules/:key/access/nodesThe permission state of listed rows: { "folderIds": ["..."], "documentIds": ["..."] }, up to 500 of each. Answers nodes keyed folder:<id> and document:<id>, each with mode (own or inherit), managed: "sync" when a source owns it and the number of entries of its own list (0 while it inherits). Ids that are not in the knowledge base are left out
POST /api/rag/modules/:key/access/audienceWho each key stands for: { "principals": ["user:...", "x:corp:all"] }, up to 1000 keys, invalid ones left out. Answers audience keyed by the key as sent, with its kind, a label, a detail, whether it exists and people, the active console people the key reaches (null for everyone, for tokens, and for a directory key unless the caller is a Knowledge Engine admin of the whole workspace)
GET /api/rag/modules/:key/access/principalsPeople who can open the project, groups or API tokens to add to a list: type (user, group or token), q, limit (1 to 50, 20 by default). Answers items with the principal key to store

A folder or a document with its own permissions and no entries is closed: nobody reads it apart from the administrators with the exception above. The summary lists up to 50 closed items, folders first and then documents, newest first, and sets closedComplete: false when the list is cut or the scan for closed documents stopped before its end.

External directories ​

An external directory holds the users and groups of another system, such as the people and groups a SharePoint source reads from its site's directory, so that permissions can name them (x:<directory>:...). Directories belong to the workspace, not to one project, and only its Knowledge Engine admins manage them. A person holds the keys of the directory users they are matched to:

  1. The directory's userMatch rules, in order, compare one of the person's values (email, or externalId: their SSO or LDAP id) with a field of the directory's users (email, upn, id or attr:<name>). The first rule that finds users decides. Without rules a person is matched by email to email, then by email to upn. The matched users' groups count too (nested ones included), and so does x:<directory>:all for members, not guests.
  2. A console group whose external id is the id of a directory group stands for that group, unless the directory turns it off ("matchGroupsByExternalId": false).
  3. A link connects a console user or group to a directory user or group by hand.

An external account (a person of a host application, see external users) is matched by groups and links only, not by the rules.

The users of a directory are reported by an integration, such as a SharePoint source of the Connectors module (Enterprise). Without one, an externalId to id rule still matches a person by their SSO or LDAP id, and links work too. A change of rules or links applies to the next query (a person's keys are kept for up to 15 seconds); no document is rewritten.

RouteDoes
GET /api/rag/identity/domainsLists the directories
PUT /api/rag/identity/domains/:domainKeyCreates or changes one: label, userMatch, matchGroupsByExternalId
DELETE /api/rag/identity/domains/:domainKeyDeletes one, with the permissions that name it
GET /api/rag/identity/domains/:domainKey/usersLists its users (search, limit, offset)
GET /api/rag/identity/domains/:domainKey/peopleLists its users with the console people each one is matched to, by rule (rule: the position of the rule) or by link (linkId). Takes search, filter (matched or unmatched), limit (up to 200) and offset; answers users, total and a summary of the whole directory (directoryUsers, matchedUsers, consolePeople, matchedPeople, groups, the rules in force and whether they are the defaults)
POST /api/rag/identity/domains/:domainKey/previewCounts what unsaved rules would match, before they are saved: { "userMatch": [...] }, checked like a saved list (400 domain_invalid), where [] previews the default rules. Answers a preview with the matched users and people, decidedByRule (the users each rule decided) and the first 20 unmatchedUsers
GET /api/rag/identity/domains/:domainKey/groupsLists its groups, those its users belong to and those a permission names, with the number of users of each and the console groups that stand for it (search, limit, offset)
GET /api/rag/identity/domains/:domainKey/linksLists its links with the names of both ends, newest first
GET /api/rag/identity/console-peopleConsole users or groups to link: type (user or group), q, limit (1 to 50, 20 by default)
GET /api/rag/identity/linksLists the links (domain, consoleKind, consoleId)
POST /api/rag/identity/linksAdds one: domain, externalKind and externalId, consoleKind and consoleId (each kind user or group)
DELETE /api/rag/identity/links/:linkIdRemoves one

A directory key has up to 64 lower-case letters, digits, ., _ and -, and starts with a letter or a digit. A directory cannot be deleted while it is all that the top level of a knowledge base names (409 domain_in_use): give that knowledge base other permissions first. What a connector source maintains (its directory, its folders, and their documents and permissions) is changed only by that source (409 domain_managed_by_source, folder_managed_by_source, document_managed_by_source, acl_managed_by_source).

Work that used documents not open to everyone ​

Work that read documents not open to everyone is shown in full only to the person who asked and to the administrators of those knowledge bases: sessions, background runs, reminders, traces, model logs, and evaluation, red-team and analysis results. With adminBypass: false it is the person who asked alone, and an API token never counts as an administrator. Anyone else sees such a row without its content, opening it answers 403 session_restricted, and only those people answer its pending approvals. Snapshots leave such sessions out, and the EU AI Act compliance report leaves out such red-team attempts. While an agent works with such documents, it writes no memory that other people share.

Other services ​

  • A crawler sends pages into a knowledge base with access control only when one of its administrators sets the crawler up (403 kb_access_controlled otherwise). There a page replaces only a page the same crawler sent.
  • An evaluation run on a RAG target reads as the person who started it. Generating a dataset from a knowledge base uses only documents open to everyone.
  • The stored files and the vector index of a knowledge base with access control are read through the knowledge base. The file routes serve its files, and the vector routes query and copy its index, only to its administrators while the admin exception is on, and never to an API token. Anyone else gets 404 for a file and 403 kb_access_controlled for the index, and no other knowledge base can be put on that index.

In the console ​

Open Data → Knowledge Engine, pick a knowledge base and use these parts of the screen:

  • The Access tab appears for people with Knowledge Engine admin in the project. Its cards are Document permissions (the Enforce document permissions switch and the Admins of this knowledge engine read everything switch, which is the adminBypass setting), Default access (who reads what has no permissions of its own), summary tiles (Folders with own permissions, Documents with own permissions, Synced from connectors, Readable by nobody), Check access (pick a person and a document to see why they can or cannot read it) and Permissions from connectors.
  • The Documents tab shows folders. New folder creates one. The Access column shows where each folder or document stands, and a folder's actions menu and a document's menu hold Permissions… (shown as Permissions (read-only) for what a connector source maintains), which opens the permission editor.
  • The History tab lists the knowledge base's queries. Knowledge Engine admins of the project (and tenant owners and administrators) see everyone's queries; everyone else sees only the queries they made, and the dashboard says so. The query history routes answer scope: "all" or scope: "own" to match.

Enterprise connector sources ​

A source of the Connectors module (Enterprise), such as SharePoint, can bring the permissions of its files with it. The source keeps its permissions, its directory and its folders up to date, and they change only at the source. See SaaS apps for SharePoint and Knowledge sources for how sources feed a knowledge base.

Studio · Pulse · Console · Agent SDK and more — the Cognipeer documentation hub