Back to blog
RAG Systems

RAG Access Control: How to Keep Employees Out of Each Other's Documents

Authorization must constrain retrieval before a model receives context

Trusted identity, policy-derived scope, eligible evidence, revocation and fail-closed routes

Original ACL-RAG-8 workflow with permission-aware pseudocode and acceptance gates
RAG access control, permission-aware retrieval, RAG permissions, document access, RAG security and ACL-RAG-8
Primary nodePermission-aware evidence routing
Routing modeACL-RAG-8
StatusPUBLISHED
Separate document zones pass through a permission gateway before a verified RAG answer is returned
ACL_RAG_8_V01: tenant, entitlement, lifecycle and source policy constrain evidence before ranking and answer synthesis.
TERMINAL_PREVIEW.LOG
$ enforce rag-access --contract ACL-RAG-8
> resolve: session / subject / tenant / entitlements
> evaluate: purpose / collection / lifecycle / policy
> retrieve: eligible passages only
> verify: isolation / citation / revocation / trace
> route: answer / deny / clarification / review
Permission-aware RAG architecture

RAG access control is not a prompt instruction that says "do not reveal confidential information." A model can only use the context it receives, so the production boundary must be enforced before retrieval candidates become model context. If an employee can retrieve a document from another tenant, team or lifecycle state, a polite final answer does not repair the leak.

This guide addresses the technical question of RAG access control: identity, policy, document permissions, retrieval and operational testing. For a broader RAG delivery discussion, see RAG systems. Teams that need an architecture review can start with an AI engineering brief; this article supports that commercial page with technical criteria rather than replacing it.

Start with an authorization decision, not with similarity search

Every request should arrive at retrieval with a trusted, server-derived subject. A useful request record contains a tenant or organization boundary, immutable user ID, current role or entitlements, purpose where applicable, session and policy version. Client-supplied role names, document IDs and filters are input to validate, not authority to trust.

Treat the decision as a separate contract:

json
{
  "subject": { "tenantId": "north", "userId": "u_42", "roles": ["support"] },
  "resourceScope": { "collections": ["help-center"], "lifecycle": ["current"] },
  "policyVersion": "access-2026-08",
  "decision": "allow-retrieve"
}

The identity service, application authorization layer and retrieval service may be separate components, but they must agree on what the record means. Do not convert a role into an unbounded vector-store filter in browser code. Do not silently replace a missing scope with a larger default corpus. An incomplete or unverifiable scope should lead to a controlled denial, clarification or human route.

ACL-RAG-8: an authorization-first retrieval architecture

ACL-RAG-8 is an engineering sketch for keeping the boundary explicit from request to answer:

text
REQUEST + authenticated session
  -> resolve server-side subject, tenant and active entitlements
  -> evaluate policy for retrieval purpose and collection
  -> construct a signed / trusted retrieval scope
  -> filter candidates by tenant, ACL, lifecycle and source version
  -> rank only the eligible set
  -> select citable evidence and verify claim coverage
  -> answer | deny | ask for clarification | request review

Filtering after top-k retrieval is unsafe as a default because unauthorized content may affect traces, caches, reranking inputs or downstream observability. Prefer an engine-level filter that is derived from the trusted scope. If a storage engine cannot express an essential entitlement accurately, place a deterministic policy gate before it, or narrow the corpus architecture. Similarity score is not permission.

Document ingestion has an equally important role. Give each source and passage a stable source ID, version, tenant, collection, access attributes, lifecycle and human-openable locator. A chunk inherits access from an authoritative document record; it must not retain stale permissions when a user is removed or a document is archived. The related guide to metadata and filters in RAG explains why these fields must constrain retrieval rather than decorate it.

Model permissions as data relationships, not only role labels

Role-based access control is often a useful first layer, but production policy commonly includes multiple relationships:

RelationshipExampleRetrieval implication
TenantTwo customers share one indexCandidate must match the trusted tenant boundary
RoleSupport can read approved help articlesRole resolves to an explicit permitted collection or action
Resource ACLOnly a project team may read a design noteCandidate must match document or collection membership
LifecycleDraft policy is not customer-facingSuperseded, draft or quarantined versions are ineligible
PurposeA privileged export needs a distinct approvalPurpose is evaluated server-side, not inferred from a prompt

Avoid flattening every rule into long-lived vectors of user IDs when membership changes frequently. Keep the source of truth for membership and use a reconciliation process that can revoke or re-index affected passages. Conversely, do not assume a coarse role protects a document-level exception. The right shape depends on corpus size, change rate and the failure cost; the invariant is that a candidate cannot become eligible merely because it is semantically close.

Failure modes worth testing before a launch

Cross-tenant filter omission. A developer tests one workspace only and forgets the tenant predicate in a new retrieval path. The control is a mandatory trusted-scope constructor, integration tests with two tenants and a fail-closed default when tenant is absent.

Stale entitlement after revocation. A user loses access, but cached chunks or a background index retain the old ACL. Record policy and membership versions, set bounded cache lifetimes, reconcile changed documents and test a real revocation followed by the same query.

Authorization after retrieval. A UI hides a cited source after ranking, while the model has already seen it. Move enforcement upstream: unauthorized passages never enter retrieval results, reranking inputs, prompts or unredacted diagnostics.

Client-controlled scope. A request accepts department=finance from the browser as the effective scope. Resolve department and entitlements from the authenticated server session, then validate optional narrowing filters against that scope.

Fallback widens the corpus. An empty result triggers a friendly search across all documents. A no-answer is safer than broadening access. Any fallback must be explicitly policy-approved and independently tested.

Logs become a secondary leak. Retrieval traces may include titles, snippets or query text. Redact or minimize payloads, apply access controls to observability and test operator roles separately from end-user roles.

Build an authorization acceptance set

An access test set should be based on real policy relationships, with harmless fixture documents that are clearly distinguishable. Cover allowed retrieval, denied retrieval, a document-level exception, lifecycle change, membership removal, stale cache simulation, empty result and a user who belongs to two permitted scopes. Run equivalent prompts that differ only in identity; the expected result should change because the policy changes, not because the wording changes.

GateEvidence to retain
Trusted identityserver-derived subject, session and policy version
Eligibilitytenant, ACL, lifecycle and source-version decision before ranking
Isolationdenied sources are absent from candidates, context, citations and traces
Revocationchanged membership is observed within the documented recovery boundary
Fallbackno result never silently widens the accessible corpus
Operationsnamed owner for policy changes, incidents, audit review and rollback

Measure allow and deny outcomes separately. A high answer-quality score cannot demonstrate isolation. For sensitive use cases, review the threat model and audit requirements with the organization that owns the data; this article is an architecture guide, not legal or compliance advice.

A bounded production rollout

Begin with one workflow, a small collection set and a small number of named roles. Pin policy, ingestion and index configurations for the test. Add a kill switch or route that returns a bounded no-answer while a policy incident is investigated. Before expansion, verify that revocation, re-indexing, cache invalidation and trace redaction work under the same production-like path that serves real requests.

ts
const scope = await resolveTrustedScope(serverSession, request.purpose);
if (!scope.isComplete) return { route: "deny-or-clarify" };

const candidates = await retrieve({
  query: request.query,
  tenantId: scope.tenantId,
  allowedCollections: scope.collections,
  allowedSubjects: scope.entitlements,
  lifecycle: "current",
});

if (candidates.some((item) => !policyAllows(item, scope))) throw new Error("policy breach");
return composeCitedAnswer(selectEvidence(candidates));

This code is a control sketch, not a universal implementation. The meaningful production criteria are server-trusted identity, deterministic eligibility before model context, observable revocation and a safe refusal path. Those are the questions to bring to a RAG architecture review before treating an internal assistant as ready for wider access.

CODE_BLOCK.TXT
require(scope.isServerTrusted && scope.tenantId);
require(policy.allows(request.purpose, scope));
require(candidate.tenantId === scope.tenantId);
require(candidate.lifecycle === "current");
require(testSet.allowed && testSet.denied && testSet.revoked);
require(testSet.emptyResult && testSet.traceRedaction);

if (!scope.isComplete) route = "deny-or-clarify";
if (!evidence.isPermitted) route = "fail-closed";