---
name: fga-rebac-authorization-expert
description: "Expert guide for Fine-Grained Authorization (FGA), Google Zanzibar Relationship-Based Access Control (OpenFGA, SpiceDB, Permify), Cedar policy engines, and permission-aware RAG retrieval / Panduan ahli otorisasi granular ReBAC (OpenFGA, SpiceDB) dan retrieval RAG sadar-izin."
author: "Roedy Rustam"
version: "4.4.2"
---
# Fine-Grained Authorization (FGA) & ReBAC Expert (2026 Zanzibar Edition)
[English](#english) | [Bahasa Indonesia](#bahasa-indonesia)
---
## English
### Orchestration & Integration
- **Identity & Authentication**: `authentication-identity-expert`, `passkeys-webauthn-identity-expert`, `zero-trust-secret-vault`
- **Multi-Tenant SaaS & Database**: `saas-multi-tenant`, `database-orm-expert`, `supabase-security-expert`
- **Permission-Aware AI & RAG**: `vector-db-rag-expert`, `graph-rag-knowledge-expert`, `ai-safety-governance-expert`
- **Formal Verification & Lifecycle**: `formal-spec-z3-verifier`, `brainstorming`, `zero-to-prod-orchestrator`, `session-memory-manager`
### Description
Enterprise authorization engineering guide for **Relationship-Based Access Control (ReBAC)** modeled on **Google Zanzibar** (**OpenFGA**, **SpiceDB**, **Permify**) and attribute/policy engines (**AWS Cedar**, **Cerbos**). Moves beyond flat `user.role === 'admin'` checks to model nested organizational hierarchies (`Organization -> Team -> Folder -> Document`), sub-millisecond permission checks (`Check(user, relation, object)`), and **Permission-Aware Vector RAG** so AI agents never leak unauthorized documents across users.
### Trigger Conditions
- Designing B2B SaaS permissions with nested inheritance (Workspace $\rightarrow$ Project $\rightarrow$ Document sharing).
- Integrating OpenFGA, SpiceDB, or AWS Cedar into API middlewares.
- Enforcing document-level access control on pgvector / RAG knowledge retrieval pipelines.
- Replacing brittle, deeply nested SQL permission joins with relationship tuples.
---
### Authorization Paradigm Selection Matrix
| Paradigm | Engine Examples | Granularity | Best Use Case |
| :--- | :--- | :---: | :--- |
| **RBAC (Role-Based)** | Custom JWT claims, Clerk Org Roles | Coarse | Simple tenant roles (`owner`, `admin`, `member`) |
| **ABAC (Attribute-Based)** | AWS Cedar, Cerbos, OPA | Medium-High | Context rules (IP range, time window, department, spend limit) |
| **ReBAC (Relationship-Based)** | OpenFGA, SpiceDB (Zanzibar) | Ultra-Fine | Google Drive / Notion / Linear nested resource sharing & graphs |
---
### Core Implementation Patterns
#### 1. OpenFGA Authorization Model DSL (Nested Inheritance)
```dsl
model
schema 1.1
type user
type organization
relations
define admin: [user]
define member: [user] or admin
type folder
relations
define org: [organization]
define owner: [user]
define editor: [user] or owner or admin from org
define viewer: [user] or editor or member from org
type document
relations
define parent_folder: [folder]
define owner: [user]
define can_write: [user] or owner or editor from parent_folder
define can_read: [user] or can_write or viewer from parent_folder
```
---
#### 2. Type-Safe ReBAC Enforcement & Permission-Aware RAG Pre-Filter (TypeScript)
Never perform vector similarity search first and filter unauthorized chunks in memory afterward (which starves top-K results). Always resolve authorized object IDs or security principals first and push them into the vector query filter:
```typescript
// src/authz/fga-client.ts
import { OpenFgaClient } from '@openfga/sdk';
const fgaClient = new OpenFgaClient({
apiUrl: process.env.FGA_API_URL ?? 'http://localhost:8080',
storeId: process.env.FGA_STORE_ID!,
authorizationModelId: process.env.FGA_MODEL_ID!,
});
export async function assertDocumentPermission(params: {
userId: string;
documentId: string;
relation: 'can_read' | 'can_write';
}): Promise {
const { allowed } = await fgaClient.check({
user: `user:${params.userId}`,
relation: params.relation,
object: `document:${params.documentId}`,
});
if (!allowed) {
throw new Error(`Forbidden: user:${params.userId} lacks ${params.relation} on document:${params.documentId}`);
}
}
export async function listAccessibleDocumentIds(userId: string): Promise {
const response = await fgaClient.listObjects({
user: `user:${userId}`,
relation: 'can_read',
type: 'document',
});
return (response.objects ?? []).map((obj) => obj.replace(/^document:/, ''));
}
```
---
#### 3. SpiceDB Zanzibar Client with ZedToken Consistency Routing (TypeScript)
Prevent the classic "New Enemy" problem (stale read allowing revoked access) by propagating `ZedToken` across write-to-read causal boundaries:
```typescript
// src/authz/spicedb-rebac-router.ts
export interface ZanzibarCheckRequest {
resourceType: 'workspace' | 'project' | 'document';
resourceId: string;
relation: 'viewer' | 'editor' | 'admin';
subjectType: 'user';
subjectId: string;
atZedToken?: string;
}
export interface ZanzibarWriteTuple {
resourceType: 'workspace' | 'project' | 'document';
resourceId: string;
relation: string;
subjectType: 'user' | 'team';
subjectId: string;
}
export class SpiceDbZanzibarRouter {
private readonly endpoint: string;
private readonly presharedKey: string;
constructor(endpoint: string, presharedKey: string) {
this.endpoint = endpoint;
this.presharedKey = presharedKey;
}
public async checkPermission(req: ZanzibarCheckRequest): Promise<{ allowed: boolean; zedToken: string }> {
const payload = {
resource: {
objectType: req.resourceType,
objectId: req.resourceId,
},
permission: req.relation,
subject: {
object: {
objectType: req.subjectType,
objectId: req.subjectId,
},
},
consistency: req.atZedToken
? { atExactSnapshot: { token: req.atZedToken } }
: { minimizeLatency: true },
};
const res = await fetch(`${this.endpoint}/v1/permissions/check`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.presharedKey}`,
},
body: JSON.stringify(payload),
});
if (!res.ok) {
const errText = await res.text();
throw new Error(`[SpiceDB] CheckPermission failed HTTP ${res.status}: ${errText}`);
}
const data = (await res.json()) as {
permissionship: 'PERMISSIONSHIP_HAS_PERMISSION' | 'PERMISSIONSHIP_NO_PERMISSION';
checkedAt: { token: string };
};
return {
allowed: data.permissionship === 'PERMISSIONSHIP_HAS_PERMISSION',
zedToken: data.checkedAt?.token ?? '',
};
}
public async writeRelationshipTuples(
tenantId: string,
tuples: readonly ZanzibarWriteTuple[]
): Promise {
const updates = tuples.map((t) => ({
operation: 'OPERATION_TOUCH',
tuple: {
resource: {
objectType: `${tenantId}/${t.resourceType}`,
objectId: t.resourceId,
},
relation: t.relation,
subject: {
object: {
objectType: t.subjectType,
objectId: t.subjectId,
},
},
},
}));
const res = await fetch(`${this.endpoint}/v1/relationships/write`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.presharedKey}`,
},
body: JSON.stringify({ updates }),
});
if (!res.ok) {
const errText = await res.text();
throw new Error(`[SpiceDB] WriteTuples failed HTTP ${res.status}: ${errText}`);
}
const data = (await res.json()) as { writtenAt: { token: string } };
return data.writtenAt.token;
}
}
```
---
### Verification Checklist
- [ ] Every resource mutation endpoint verifies object-level authorization (`Check(user, can_write, object)`) to prevent IDOR vulnerabilities.
- [ ] Vector RAG pipelines filter embeddings by authorized document IDs (`WHERE document_id = ANY($1)`) prior to LLM context injection.
- [ ] Relationship tuples are deleted atomically within the same saga/outbox flow when underlying database entities are deleted.
- [ ] Zanzibar consistency tokens (`ZedToken` / `consistency: HIGHER_CONSISTENCY`) are passed after permission mutations to prevent New-Enemy stale reads.
### Sovereign Execution, Token Efficiency & Invariants
| Dimension | Sovereign Mandate & Deterministic Contract |
| :--- | :--- |
| **Frontier Model Cascade** | High Fast / High (`Grok 4.7 High Fast`, `Claude Sonnet 5.5 High`, `Gemini 4 Pro`) |
| **Availability Fallback** | `Gemini 4 Pro` -> `Gemini 3.8 Flash`; `Claude Opus 5.5` -> `Claude Opus 4.6`; `Grok 4.7` -> `Grok 4.6 High Fast` (Zero unhandled missing-model errors) |
| **KV-Cache & Token Protocol** | Pin static instructions & schemas at prompt prefix (`kv-cache-prefix-optimizer`); pass surgical `CONTEXT_MAP.md` slices (<250 tokens/call) during Swarm Fan-Out |
| **SaaT CLI & MCP Dispatch** | CLI: `vibes skill exec fga-rebac-authorization-expert ` / MCP: `vibes_skill_dispatch`, `vibes_critic_validate`, `vibes_self_heal`, `vibes_eval_sandbox`, `vibes_verify_invariants` |
| **NFR & Anti-Slop Invariants** | Zero OWASP Top 10 vectors, 0 hardcoded secrets, >= 90% branch coverage on domain logic, 0 Anti-Slop violations; 100% complete zero-placeholder output verified via `node scripts/check-anti-slop.js --strict` |
---
---
## Bahasa Indonesia
### Integrasi Orkestrasi
- **Identitas & Autentikasi**: `authentication-identity-expert`, `passkeys-webauthn-identity-expert`, `zero-trust-secret-vault`
- **SaaS Multi-Tenant & Database**: `saas-multi-tenant`, `database-orm-expert`, `supabase-security-expert`
- **AI & RAG Sadar-Izin**: `vector-db-rag-expert`, `graph-rag-knowledge-expert`, `ai-safety-governance-expert`
- **Verifikasi Formal & Siklus Hidup**: `formal-spec-z3-verifier`, `brainstorming`, `zero-to-prod-orchestrator`, `session-memory-manager`
### Deskripsi
Panduan rekayasa otorisasi enterprise untuk **Relationship-Based Access Control (ReBAC)** berbasis **Google Zanzibar** (**OpenFGA**, **SpiceDB**, **Permify**) serta mesin kebijakan atribut (**AWS Cedar**, **Cerbos**). Mencakup pewarisan izin bertingkat (`Organisasi -> Folder -> Dokumen`) dan **Permission-Aware Vector RAG** agar agen AI tidak pernah membocorkan dokumen lintas pengguna.
### Panduan Arsitektur Inti
1. ** melampaui RBAC Statis**: Gunakan tuple relasi `(user, relation, object)` untuk memodelkan berbagi dokumen kolaboratif ala Google Drive atau Linear.
2. **RAG Sadar-Otorisasi**: Selalu evaluasi daftar dokumen yang diizinkan (`listObjects`) dan pasang filter `WHERE document_id = ANY(...)` pada kueri pgvector sebelum potongan teks dikirim ke prompt LLM.
3. **Pencegahan Masalah New-Enemy**: Gunakan token konsistensi (`ZedToken`) saat pencabutan akses agar cache otorisasi langsung diperbarui.
### Daftar Periksa Verifikasi (Checklist)
- [ ] Setiap endpoint memeriksa izin tingkat objek untuk mencegah celah IDOR.
- [ ] Pipeline RAG memfilter dokumen berdasarkan izin akses pengguna sebelum masuk ke konteks LLM.
- [ ] Tuple relasi dihapus secara sinkron ketika entitas di database utama dihapus.
### Matriks Eksekusi Berdaulat, Efisiensi Token & Invarian
| Dimensi | Mandat Berdaulat & Kontrak Deterministik |
| :--- | :--- |
| **Kaskade Model Frontier** | High Fast / High (`Grok 4.7 High Fast`, `Claude Sonnet 5.5 High`, `Gemini 4 Pro`) |
| **Invarian Fallback Ketersediaan** | `Gemini 4 Pro` -> `Gemini 3.8 Flash`; `Claude Opus 5.5` -> `Claude Opus 4.6`; `Grok 4.7` -> `Grok 4.6 High Fast` (Bebas gagal saat model belum tersedia/kuota penuh) |
| **Protokol Hemat Token & KV-Cache** | Kunci instruksi & skema statis di prefix awal (`kv-cache-prefix-optimizer`); kirim potongan `CONTEXT_MAP.md` (<250 token/panggilan) saat Fan-Out |
| **Eksekusi SaaT CLI & MCP** | CLI: `vibes skill exec fga-rebac-authorization-expert ` / MCP: `vibes_skill_dispatch`, `vibes_critic_validate`, `vibes_self_heal`, `vibes_eval_sandbox`, `vibes_verify_invariants` |
| **Invarian NFR & Anti-Slop** | Nol celah OWASP Top 10, 0 kredensial hardcoded, cakupan pengujian >= 90% pada logika domain, 0 pelanggaran Anti-Slop; kode 100% tuntas tanpa placeholder diverifikasi melalui `node scripts/check-anti-slop.js --strict` |