OpenFGA em uma frase
OpenFGA (Open Fine-Grained Authorization) é a implementação ReBAC criada pela Auth0/Okta em 2022 e doada ao CNCF (Sandbox) no mesmo ano. Apache 2.0. Inspirada no Zanzibar do Google, com foco em DX (Developer Experience) — modeling language simplificada, Playground online, SDKs em 9+ linguagens.
Modeling Language: simples por design
model
schema 1.1
type user
type organization
relations
define admin: [user]
define member: [user]
define can_view: admin or member
type folder
relations
define parent: [folder, organization]
define owner: [user]
define editor: [user]
define viewer: [user]
define can_edit: owner or editor or parent.can_edit
define can_view: viewer or can_edit or parent.can_view
type document
relations
define parent: [folder]
define owner: [user]
define editor: [user]
define viewer: [user]
define can_edit: owner or editor or parent.can_edit
define can_view: viewer or can_edit or parent.can_viewA diferença DX é tangível: lê como inglês. Comparado ao SpiceDB — equivalentes, mas o primeiro é mais didático.
API: 5 verbos canônicos
| API | Função | Quando |
|---|---|---|
| Write | CRUD em tuplas (compartilhar, adicionar membro) | A cada ação de share/role mgmt |
| Check | user pode fazer ação? — single decision | Path do request HTTP, middleware |
| BatchCheck | N checks em paralelo numa chamada | GraphQL com N entidades, dashboard |
| ListObjects | Quais recursos do tipo T user pode acessar? | UI de listagem ("Meus docs") |
| ListUsers | Quem tem acesso a este recurso? | UI de compartilhamento, admin |
| Expand | Árvore de derivação da permission | Debug, auditoria |
| Read | Listar tuplas brutas (paginated) | Compliance, export |
Exemplo end-to-end: SDK Node
import { OpenFgaClient, CredentialsMethod } from '@openfga/sdk';
const fga = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL!,
storeId: process.env.FGA_STORE_ID!,
authorizationModelId: process.env.FGA_MODEL_ID!,
credentials: {
method: CredentialsMethod.ClientCredentials,
config: {
clientId: process.env.FGA_CLIENT_ID!,
clientSecret: process.env.FGA_CLIENT_SECRET!,
apiTokenIssuer: 'auth.fga.dev',
apiAudience: 'https://api.us1.fga.dev/',
},
},
});
// 1. Compartilhar doc com Bob como editor
await fga.write({
writes: [
{ user: 'user:bob', relation: 'editor', object: 'document:report-q1' },
],
});
// 2. Checar permissão de Bob no doc
const { allowed } = await fga.check({
user: 'user:bob',
relation: 'can_view',
object: 'document:report-q1',
});
if (!allowed) throw new ForbiddenError();
// 3. Listar documents que Bob pode visualizar
const { objects } = await fga.listObjects({
user: 'user:bob',
relation: 'can_view',
type: 'document',
});
// → ['document:report-q1', 'document:notes', ...]Conditional tuples (ABAC dentro do ReBAC)
Como em SpiceDB caveats, OpenFGA permite anexar condições CEL às tuplas. Use case clássico: acesso temporário (até timestamp X) ou IP-restricted.
model
schema 1.1
type user
type document
relations
define viewer: [user, user with non_expired_grant]
define can_view: viewer
condition non_expired_grant(current_time: timestamp, grant_expires_at: timestamp) {
current_time < grant_expires_at
}// Adicionar viewer COM condição
await fga.write({
writes: [{
user: 'user:guest',
relation: 'viewer',
object: 'document:demo',
condition: {
name: 'non_expired_grant',
context: { grant_expires_at: '2026-12-31T23:59:59Z' },
},
}],
});
// Check passando o contexto runtime
await fga.check({
user: 'user:guest',
relation: 'can_view',
object: 'document:demo',
context: { current_time: new Date().toISOString() },
});Consistência: ImplicitTuples vs OpenFGA ConsistencyPreference
OpenFGA tem opção consistency no Check: MINIMIZE_LATENCY (default — pode usar cache stale) e HIGHER_CONSISTENCY (força leitura recente do storage). Não há "ZedToken/Zookie" explícito; a mitigação do new enemy problem fica por conta dessa flag.
// Path crítico (após write de revogação) — força consistência
const result = await fga.check({
user: 'user:bob',
relation: 'can_view',
object: 'document:sensitive',
consistency: 'HIGHER_CONSISTENCY',
});Trade-off vs SpiceDB: ZedTokens permitem consistência granular "at_least_as_fresh ≥ X"; OpenFGA é binário (latency vs strict). Em prática, sufficient na maioria dos casos, mas conheça a diferença ao desenhar.
Playground: o killer feature DX
play.fga.dev é o playground oficial — UI online onde você cola o modelo, adiciona tuplas, executa checks e visualiza o grafo. Não exige login para uso básico. É a melhor maneira de prototipar autorização sem instalar nada — superior em DX ao zed CLI para iteração inicial.
OpenFGA vs SpiceDB: a decisão
📋 SaaS B2B precisando ReBAC com 10-50k usuários e 1-5 desenvolvedores no time
DX superior (Playground, modeling simples), managed cloud reduz ops, conditional tuples cobrem casos ABAC. SpiceDB ganha quando você precisa de CockroachDB nativo, ZedTokens granulares, ou já tem time forte em SRE.
Alt: OpenFGA self-host —
Alt: Auth0 FGA cloud —
Alt: SpiceDB —
Alt: Permit.io —
| Aspecto | OpenFGA | SpiceDB |
|---|---|---|
| Linguagem core | Go | Go |
| Origem | Auth0/Okta → CNCF | Authzed (Red Hat alumni) |
| Modeling | DSL declarativa, prosa-like | DSL com operadores +/-/& |
| Playground online | play.fga.dev (✓) | authzed.com/playground (✓) |
| CockroachDB nativo | — (use Citus) | ✓ |
| Conditional rules | Conditional tuples (CEL) | Caveats (CEL) |
| Consistência granular | Latency vs HigherConsistency (binário) | ZedTokens (at_least_as_fresh granular) |
| Managed cloud | Auth0 FGA | Authzed Dedicated / Serverless |
| CNCF | Sandbox (2022) | — (governança Authzed) |
| Maturidade modeling complexo | Boa | Excelente |
Operando OpenFGA self-host
# Docker — desenvolvimento
docker run -p 8080:8080 -p 8081:8081 -p 3000:3000 \
openfga/openfga:latest run
# Postgres backend — produção
docker run -e OPENFGA_DATASTORE_ENGINE=postgres \
-e OPENFGA_DATASTORE_URI=postgres://user:pass@host/openfga \
-p 8080:8080 -p 8081:8081 \
openfga/openfga:latest run
# Health
curl http://localhost:8080/healthz
# → {"status":"SERVING"}
# CLI
fga store create --name "saas-prod"
fga model write --store-id 01H... --file model.fgaPadrões anti-pattern em OpenFGA
- Um store global compartilhado entre tenants: difícil isolar, vaza tuplas em queries de admin. Use 1 store por tenant em SaaS sério.
- ListObjects em tipos com 100k+ objetos: o fan-out pode demorar segundos. Combine com indexação no app (search engine) e use FGA só para checagem fina.
- Não versionar o modelo no git: o JSON do authorization model deve estar no repo; mudanças via PR. Sem isso, evoluir o schema vira aventura.
- Tuplas geradas dinamicamente em batch sem dedup: writes são idempotentes mas tem custo; use BatchWrite e cheque se a tupla já existe quando relevante.
Resumo executivo
- OpenFGA = implementação Zanzibar do Auth0/Okta, CNCF Sandbox 2022, Apache 2.0.
- Modeling DSL legível como prosa: .
- API: Check / BatchCheck / Write / ListObjects / ListUsers / Expand / Read.
- Conditional tuples (CEL) trazem ABAC para dentro do ReBAC — paridade com caveats SpiceDB.
- Auth0 FGA cloud = OpenFGA gerenciado: zero ops, ideal para times pequenos.
- Playground online (play.fga.dev) é o killer DX para prototipar autorização.
- Escolha vs SpiceDB: OpenFGA por DX e managed cloud; SpiceDB por modeling complexo, CRDB e ZedTokens.