> ## Documentation Index
> Fetch the complete documentation index at: https://openfga.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# RAG Authorization

> Enforce per-user permissions on retrieval-augmented generation. Filter retrieved documents through OpenFGA before they reach the model.

export const OpenFGACodeBlock = ({code, title}) => {
  const [ready, setReady] = useState(false);
  useEffect(() => {
    if (window.openfgaDsl) {
      setReady(true);
      return;
    }
    let script = document.querySelector('script[src="/openfga-dsl-highlight.js"]');
    const loaded = () => {
      if (window.openfgaDsl) setReady(true);
    };
    if (!script) {
      script = document.createElement('script');
      script.src = '/openfga-dsl-highlight.js';
    }
    script.addEventListener('load', loaded);
    if (!script.isConnected) document.head.appendChild(script);
    return () => script.removeEventListener('load', loaded);
  }, []);
  const trimmed = code.replace(/^\n/, '').replace(/\n$/, '');
  const tokens = ready && window.openfgaDsl ? window.openfgaDsl.tokenize(trimmed) : [{
    text: trimmed,
    type: 'default'
  }];
  const colors = ready && window.openfgaDsl ? window.openfgaDsl.colors : {};
  const themeStyle = {
    '--openfga-dark-background': colors.background,
    '--openfga-dark-default': colors.default,
    '--openfga-dark-accent': colors.green
  };
  return <div className="openfga-code-viewer" style={themeStyle}>
      {title && <div className="openfga-code-viewer__title">{title}</div>}
      <div className="openfga-code-viewer__code" data-language="dsl">
        {tokens.map((t, i) => <span className="openfga-code-token" data-token={t.type || 'default'} key={i} style={{
    '--openfga-dark-token-color': t.color || colors.default
  }}>
            {t.text}
          </span>)}
      </div>
    </div>;
};

Retrieval-augmented generation pipelines retrieve documents from a data set and hand them to the model as context. If the data set contains anything the asking user shouldn't see, the model will happily summarize it back to them. The fix is to **filter retrieval results by the user's permissions** before the model ever sees them.

## The pattern

1. The user asks the agent a question.
2. The retriever pulls candidate documents (vector search, keyword, hybrid).
3. **OpenFGA filters** the candidates: for each candidate `doc:X`, check whether `user:Y` has `can_view`. Or call [list-objects](/docs/interacting/relationship-queries) once to get the full set of documents this user can read, then intersect.
4. Only the surviving documents are passed to the model as context.

The same model and prompt now produce different — and correct — answers per user, because the context they see is scoped to what they're allowed to see.

## Simplified model

<OpenFGACodeBlock
  code={`type user

type folder
\x20 relations
\x20   define parent: [folder]
\x20   define viewer: [user]
\x20   define can_view: viewer or can_view from parent

type document
\x20 relations
\x20   define parent: [folder]
\x20   define viewer: [user]
\x20   define can_view: viewer or can_view from parent`}
/>

Folders nest arbitrarily deep — a viewer on a top-level folder inherits `can_view` on every descendant folder and document. Before retrieval reaches the model, call `list-objects(user:alice, can_view, document)` to get every document Alice can read, then intersect with the retriever's candidate set.

## Why list-objects matters here

For small set of documents, per-document checks are fine. For larger ones, `list-objects` is dramatically cheaper: one call returns the full set of documents the user can read, and you intersect that with the retriever's candidates. This is exactly the case OpenFGA's reverse queries are designed for.

## Conditions and contextual data

If access depends on document attributes (classification, region, time window) as well as relationships, use [conditions](/docs/modeling/conditions) and [contextual tuples](/docs/interacting/contextual-tuples). Both are evaluated at check time without round-tripping back to your application.

## Related reading

* [RAG authorization modeling guide](/docs/modeling/agents/rag-authorization)
* [AI agent authorization](/docs/use-cases/ai-agent-authorization)
* [List-objects API](/docs/interacting/relationship-queries)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.