MainSDK
Search⌘K
Integrations

OpenFGA

Use OpenFGA for relationship-based MainSDK access on your existing store and model - main.yaml, adopt, testing and swapping.

1 interface1 driverWritten guide
Updated 2026-10-28

OpenFGA is an open-source, Zanzibar-style engine for relationship-based access: "she can edit this document because her team owns the folder". Behind access, your OpenFGA model and tuples stay where they are, and MainSDK adds typed permissions, checks and audit in front. Pick it when permissions follow relationships between users, teams and records, or when your company already runs OpenFGA.

Interfaces it serves

Pick OpenFGA in main.yaml for any of these. Your calls stay the same, and you can swap later.

Before you start

  1. Run an OpenFGA server, or use a managed OpenFGA service, reachable from your app.
  2. Create a store and an authorization model, and note both IDs.
  3. Set up credentials for your app if your server requires them, and keep them in your secrets manager.

Configure

main.yaml
access:
  driver: openfga
  openfga: { api: https://fga.pinecart.internal, store: 01J…, model: 01J… }   # shape from the requirements; not in the spec yet
  models: [rebac, abac]
  fresh-after-write: true
  unreachable: { deny: true, cache: 30s }

The access spec does not define connection keys for remote engines yet, so the openfga: line may change. Credentials take secret: references.

Use it

server/folders.ts
import { access } from "mainsdk";

export async function shareFolder(user: { id: string }, folderId: string, teamId: string) {
  const folder = { type: "folder", id: folderId };
  await access.relate({ type: "team", id: teamId }, "editor", folder);
  return access.can(user, "folders.edit", folder);   // higher consistency right after the write
}

Local development and testing

mainsdk dev runs Cedar in process, so you can build without a server; run OpenFGA locally to exercise your real model. mainsdk test access runs your model tests, createTestApp() from @mainsdk/testing puts access on its fake, and chaos.on("access", { outage: true }) shows checks denying with MAIN-ACCESS-0007.

What MainSDK adds on top

  • Typed permissions from your model through mainsdk adopt access --from openfga.
  • Fresh after write: a check right after access.relate() in the same request uses higher consistency.
  • Denies when OpenFGA is unreachable, with only a short cache you set.
  • Every decision written to the audit log with the model ID.

See Permissions.

Limits and notes

  • The OpenFGA driver is a phase 1 ticket in the access spec (milestone 0.3).
  • mainsdk check flags OpenFGA 1.8.0 to 1.13.1 (CVE-2026-34972) with MAIN-ACCESS-0011; upgrade OpenFGA.
  • New tuples are written through the job outbox, so the database row and the tuple never drift apart.
  • access.raw() returns the OpenFGA client; mainsdk check lists every use.

Swap to or from it

main.yaml
access:
  driver: spicedb   # was openfga

FAQ

Do I have to move my tuples? No. They stay in your store; MainSDK sits in front.

Does this work with Auth0 FGA? Auth0 FGA is managed OpenFGA, listed in the requirements as a close relative on the same path. How the driver connects to it is not specified yet.

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet