Fine-grained authorization for AI agents.
AgentFGA decides what each agent can see and do, down to a single document, tool or record. Check every tool call, filter what reaches the model, and give agents access that expires. It speaks the OpenFGA API, so the official SDKs and CLI work unchanged.
Building with a coding agent? Paste llms.txt into it. It has the steps to deploy AgentFGA and add permission checks to your agent.
import { OpenFgaClient } from "@openfga/sdk";
const fga = new OpenFgaClient({
apiUrl, storeId, credentials,
});
// Before the agent uses a tool, check that it may.
const { allowed } = await fga.check({
user: "agent:support-bot",
relation: "can_use",
object: "tool:issue-refund",
});
// Before retrieval, find what the user may see.
const { objects } = await fga.listObjects({
user: "user:anne",
relation: "viewer",
type: "document",
});
The official OpenFGA SDK, pointed at AgentFGA.
§ 01 · Why agents
Why agents need fine-grained authorization.
An agent acts for a user, calls many tools and reads a lot of data, faster than anyone can review. Roles like “admin” are too coarse. You need to know whether this agent, acting for this user, may touch this specific thing.
01
Check every action
Ask before each tool call or write. A check takes about 6 ms on the server, and stayed that fast with 1.1 million relationships in a store.
Check · BatchCheck
02
Filter what the model sees
List every document a user may view, or check up to 50 retrieved results at once, so the model only gets what the user is allowed to read.
ListObjects · BatchCheck
03
Scoped access that expires
Give each agent its own identity and its own grants. Conditions limit a grant by time or by request details, such as access that ends after an hour.
Conditions · contextual tuples
04
One store per customer
Each customer's permissions live in their own store, kept apart from everyone else's. Stores run independently, so capacity grows with your customers.
Stores
§ 02 · How it works
Write the rules once. Check before every action.
AgentFGA uses the OpenFGA model: three steps, shown here with an agent.
-
Write your rules
Describe who can do what, once. Here: owners can view a document, and agents can get temporary access that also lets them view it.
type document relations define owner: [user] define temp: [agent with not_expired] define viewer: owner or temp -
Grant access
Store relationships as things change. Here: the support bot gets temporary access to the Q3 plan for one hour.
user: agent:support-bot relation: temp object: document:q3-plan condition: not_expired, 1h -
Check before acting
Ask before the agent reads or changes something. Here: may the support bot view the Q3 plan right now?
user: agent:support-bot relation: viewer object: document:q3-plan allowed: true
Where AgentFGA fits
Your agent or app asks AgentFGA before it acts. AgentFGA keeps the rules and relationships and answers.
Each store's data sits right next to the code that checks it, so an answer never waits on a separate database. Stores are kept apart from each other, so adding customers adds capacity.
§ 03 · Evidence
Measured, then published.
Every number comes from the test harness in the repository. The reports have the method, the caveats and the commands to rerun them.
- Check latency at the edge
- 6msOn the server, when the store shares a data center with the request.
- Largest store tested
- 1.1MRelationships in one store. Checks were as fast as in a store ten times smaller.
- Across 16 stores
- 6,799req/sWith zero errors. Capacity grows as you add customers.
- Compared with OpenFGA
- 864,827Side-by-side requests against v1.22.0. Two differences, both caused by OpenFGA.
§ 04 · Get started
Run it locally, then deploy.
AgentFGA runs on Cloudflare Workers. You need Node.js to run it locally, and a Cloudflare account to deploy it.
-
Run it on your machine
The key you put in
.dev.varsis the API token your agents and apps will send.shellnpm install echo "AGENTFGA_AUTHN_PRESHARED_KEYS=dev-key-123" > .dev.vars npm run dev # http://127.0.0.1:8787 -
Create a store
Use the official
fgaCLI, or the SDK withapiUrlset tohttp://127.0.0.1:8787. Create one store per customer.shellfga store create --name acme \ --api-url http://127.0.0.1:8787 --api-token dev-key-123 -
Deploy
Save your API keys as a secret, separated by commas, then deploy.
shellnpx wrangler secret put AGENTFGA_AUTHN_PRESHARED_KEYS npm run deploy
Configuration options
Set these as vars in wrangler.jsonc.
| Variable | Default |
|---|---|
AGENTFGA_AUTHN_METHOD | preshared. none turns off authentication, for local use only. |
AGENTFGA_AUTHN_PRESHARED_KEYS | A secret. Required when the method is preshared. |
AGENTFGA_MAX_TUPLES_PER_WRITE | 100 |
AGENTFGA_MAX_TYPES_PER_AUTHORIZATION_MODEL | 100 |
AGENTFGA_MAX_CHECKS_PER_BATCH_CHECK | 50 |
AGENTFGA_RESOLVE_NODE_LIMIT | 25 |
AGENTFGA_LIST_OBJECTS_MAX_RESULTS / _DEADLINE_MS | 1000 / 3000 |
AGENTFGA_LIST_USERS_MAX_RESULTS / _DEADLINE_MS | 1000 / 3000 |
AGENTFGA_DIAGNOSTIC_HEADERS | Unset. true adds headers showing which data centers handled each request. |
§ 05 · Compatibility
Compatible with OpenFGA.
AgentFGA covers OpenFGA's HTTP API: stores, models (schema 1.1 and 1.2), relationship tuples, Check, BatchCheck, ListObjects, ListUsers, Expand, change history, assertions and conditions. Every response, including error codes and messages, was compared with OpenFGA v1.22.0, across 864,827 side-by-side requests.
Not supported yet
- OIDC sign-in. Clients authenticate with API keys only.
- AuthZEN endpoints.
- Metrics and tracing.
- Experimental
$expressionconditions.
Works differently
- Stores that don't exist return 404. OpenFGA accepts some requests for them, such as writing a model.
- The
consistencyoption is ignored, because every read is already up to date. - StreamedListObjects sends the full result at once instead of streaming it.
- Condition errors are worded differently, and OpenFGA's cost limit for conditions isn't enforced.
- Missing condition parameters can give a different result in rare cases (157 of 864,750), because OpenFGA decides how to handle them at random.
How compatibility was tested
Test tools send identical requests to AgentFGA and to the official OpenFGA v1.22.0 server, then compare every response. npm test replays the results, so they are rechecked on every run. Testing also found 9 bugs in OpenFGA itself; COMPATIBILITY.md lists them.
| What was compared | Requests | Differences |
|---|---|---|
| Random models, relationships and queries | 864,827 | 2, both caused by OpenFGA |
| The same, with condition parameters sometimes missing | 864,750 | 159, of which 157 are OpenFGA's random choice described above |
| Malformed and edge-case requests to every endpoint | 5,020 | 0 |
| Limits, cycles, pagination and other targeted scenarios | 79 | 0 |
| All of the above against a deployed instance | 29,113 + 5,020 + 79 | 0 |
| OpenFGA's own conformance tests 171 tests | all but 18 | 0. The 18 use experimental $expression conditions. |
A full app flow with the official @openfga/sdk | 1 flow each | 0 |
An OHQ product.
OHQ researches and builds the infrastructure agents run on, and releases it as open source. AgentFGA comes first, because deciding what agents may see and do is where they carry the most risk.