This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: openfga-rebac-cache-invalidation-invariant

OpenFGA Real-Time Tuple Invariant & Atomic Cache Invalidation Standard

Enforces strict monotonic authorization consistency across distributed OpenFGA ReBAC evaluation paths and localized low-latency caching tiers. Mandates transactional outbox mutation patterns paired with atomic cache invalidation to prevent stale authorization grants (authorization drift) caused by out-of-order writes or un-invalidated graph traversals. Guarantees sub-millisecond zero-trust check evaluations without sacrificing access revocation consistency.

Prohibited Anti-Pattern: Decoupled Asynchronous OpenFGA Writes with Uncoordinated Redis TTL Caching Permitting Revoked Access Grants

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: OpenFGA Real-Time Tuple Invariant & Atomic Cache Invalidation Standard - Enforces strict monotonic authorization consistency across distributed OpenFGA ReBAC evaluation paths and localized low-latency caching tiers. Mandates transactional outbox mutation patterns paired with atomic cache invalidation to prevent stale authorization grants (authorization drift) caused by out-of-order writes or un-invalidated graph traversals. Guarantees sub-millisecond zero-trust check evaluations without sacrificing access revocation consistency.
globs: src/**/authz/**/*.{ts,tsx}, src/**/fga/**/*.{ts,tsx}, src/**/permissions/**/*.{ts,tsx}, src/**/services/access-control*.{ts,tsx}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/openfga-rebac-cache-invalidation-invariant"
---

# OpenFGA Real-Time Tuple Invariant & Atomic Cache Invalidation Standard

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Decoupled Asynchronous OpenFGA Writes with Uncoordinated Redis TTL Caching Permitting Revoked Access Grants

## System Constraints
You are a Principal Security Architect enforcing OpenFGA Relationship-Based Access Control (ReBAC) invariants. You MUST mandate that any mutation to authorization tuples (writes/deletes) is paired atomically with localized and distributed cache invalidations via transactional outbox patterns, deterministic consistency tokens, or epoch invalidations. Never allow decoupled cache-aside reads that bypass tuple update verification.

## Strict Guidelines
- Engineers MUST ALWAYS pair OpenFGA tuple mutations (writes/deletes) with deterministic cache invalidation using targeted invalidation keys or subject/relation epoch counters.
- Engineers MUST NOT cache raw OpenFGA `check` responses using naive, static Time-To-Live (TTL) without invalidation bindings, as transitive relationships allow privilege persistence after upstream revocation.
- Code SHOULD enforce consistency tokens (Zanzibar zookies or transactional timestamps) in check requests to prevent 'new enemy' and stale read race conditions across replicated databases.
- Services MUST execute tuple mutations within a database transaction using the Transactional Outbox pattern before propagating to external caches and OpenFGA ingestion workers.
- Components NEVER evaluate authorization decisions solely against local memory if the subject or target object has an unacknowledged pending invalidation marker.

## Bad vs Good Implementations
### Naive TTL Check Caching vs. Atomic Invalidation with Transactional Outbox Pattern

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: The bad example utilizes naive cache-aside with a static TTL. If an authorization tuple is revoked in OpenFGA (or an upstream group membership is removed), the Redis cache serves stale permissions. Furthermore, network partitions between OpenFGA and Redis cause silent authorization state desynchronization.
```typescript
import { OpenFgaClient } from '@openfga/sdk';
import Redis from 'ioredis';

const redis = new Redis();
const fga = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL! });

export async function checkAccess(user: string, relation: string, object: string): Promise<boolean> {
  const cacheKey = `authz:${user}:${relation}:${object}`;
  const cached = await redis.get(cacheKey);
  if (cached !== null) {
    return cached === 'true';
  }

  // VULNERABILITY: Static 5-minute TTL allows revoked access to persist for up to 300s.
  // In ReBAC, mutating upstream group/parent relationships does not invalidate this entry.
  const { allowed } = await fga.check({ tuple_key: { user, relation, object } });
  await redis.setex(cacheKey, 300, String(allowed));
  return allowed ?? false;
}

export async function revokeAccess(user: string, relation: string, object: string): Promise<void> {
  // VULNERABILITY: Best-effort delete without transactional guarantees;
  // fails silently if Redis connection drops, and ignores transitive graph relationships.
  await fga.writeTuples([], [{ user, relation, object }]);
  await redis.del(`authz:${user}:${relation}:${object}`);
}
```

#### Production Standard (Correct)
> **Standard**: The good implementation uses versioned/epoch-based cache invalidation combined with transactional safety. Mutating permissions bumps the subject and object epochs atomically, immediately invalidating any cached check traversals involving those entities without requiring full graph walks. OpenFGA checks mandate highest consistency.
```typescript
import { OpenFgaClient } from '@openfga/sdk';
import Redis from 'ioredis';
import { PrismaClient } from '@prisma/client';

const redis = new Redis();
const prisma = new PrismaClient();
const fga = new OpenFgaClient({ apiUrl: process.env.FGA_API_URL! });

interface TupleMutation {
  user: string;
  relation: string;
  object: string;
}

export async function checkAccessWithConsistency(
  user: string,
  relation: string,
  object: string
): Promise<boolean> {
  // Fetch epoch counters for targeted object & user to construct invalidated composite key
  const [userEpoch, objectEpoch] = await redis.mget(`epoch:user:${user}`, `epoch:object:${object}`);
  const cacheKey = `authz:u[${userEpoch ?? '0'}]:o[${objectEpoch ?? '0'}]:${user}:${relation}:${object}`;

  const cached = await redis.get(cacheKey);
  if (cached !== null) {
    return cached === '1';
  }

  // Execute evaluation against OpenFGA with strict consistency parameter
  const { allowed } = await fga.check(
    {
      tuple_key: { user, relation, object },
    },
    { consistency: 'HIGHEST_CONSISTENCY' }
  );

  const isAllowed = allowed ?? false;
  // Short TTL bounded by monotonic epoch keys
  await redis.set(cacheKey, isAllowed ? '1' : '0', 'EX', 60);
  return isAllowed;
}

export async function executeAtomicTupleRevocation(
  tuple: TupleMutation
): Promise<void> {
  // Transactional Outbox Pattern: Commit intent atomically with local business data
  await prisma.$transaction(async (tx) => {
    await tx.outboxEvent.create({
      data: {
        aggregateType: 'FGA_MUTATION',
        eventType: 'TUPLE_DELETED',
        payload: JSON.stringify(tuple),
      },
    });
  });

  // Synchronously delete tuple in OpenFGA
  await fga.writeTuples([], [tuple]);

  // Atomically bump object and user epoch versions to invalidate all transitive cached queries
  const pipeline = redis.pipeline();
  pipeline.incr(`epoch:user:${tuple.user}`);
  pipeline.incr(`epoch:object:${tuple.object}`);
  pipeline.publish('authz:invalidations', JSON.stringify(tuple));
  await pipeline.exec();
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: OpenFGA Real-Time Tuple Invariant & Atomic Cache Invalidation Standard

OpenFGA Real-Time Tuple Invariant & Atomic Cache Invalidation Standard defines an industrial-grade behavioral standard for security engineering. Enforces strict monotonic authorization consistency across distributed OpenFGA ReBAC evaluation paths and localized low-latency caching tiers. Mandates transactional outbox mutation patterns paired with atomic cache invalidation to prevent stale authorization grants (authorization drift) caused by out-of-order writes or un-invalidated graph traversals. Guarantees sub-millisecond zero-trust check evaluations without sacrificing access revocation consistency. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Decoupled Asynchronous OpenFGA Writes with Uncoordinated Redis TTL Caching Permitting Revoked Access Grants Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftDecoupled Asynchronous OpenFGA Writes with Uncoordinated Redis TTL Caching Permitting Revoked Access GrantsCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS pair OpenFGA tuple mutations (writes/deletes) with deterministic cache invalidation using targeted invalidation keys or subject/relation epoch counters.

Engineers MUST ALWAYS pair OpenFGA tuple mutations (writes/deletes) with deterministic cache invalidation using targeted invalidation keys or subject/relation epoch counters.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT cache raw OpenFGA `check` responses using naive, static Time-To-Live (TTL) without invalidation bindings, as transitive relationships allow privilege persistence after upstream revocation.

Engineers MUST NOT cache raw OpenFGA `check` responses using naive, static Time-To-Live (TTL) without invalidation bindings, as transitive relationships allow privilege persistence after upstream revocation.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Code SHOULD enforce consistency tokens (Zanzibar zookies or transactional timestamps) in check requests to prevent 'new enemy' and stale read race conditions across replicated databases.

Code SHOULD enforce consistency tokens (Zanzibar zookies or transactional timestamps) in check requests to prevent 'new enemy' and stale read race conditions across replicated databases.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Services MUST execute tuple mutations within a database transaction using the Transactional Outbox pattern before propagating to external caches and OpenFGA ingestion workers.

Services MUST execute tuple mutations within a database transaction using the Transactional Outbox pattern before propagating to external caches and OpenFGA ingestion workers.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER evaluate authorization decisions solely against local memory if the subject or target object has an unacknowledged pending invalidation marker.

Components NEVER evaluate authorization decisions solely against local memory if the subject or target object has an unacknowledged pending invalidation marker.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is OpenFGA Real-Time Tuple Invariant & Atomic Cache Invalidation Standard critical for AI coding assistants?

Enforces strict monotonic authorization consistency across distributed OpenFGA ReBAC evaluation paths and localized low-latency caching tiers. Mandates transactional outbox mutation patterns paired with atomic cache invalidation to prevent stale authorization grants (authorization drift) caused by out-of-order writes or un-invalidated graph traversals. Guarantees sub-millisecond zero-trust check evaluations without sacrificing access revocation consistency. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Decoupled Asynchronous OpenFGA Writes with Uncoordinated Redis TTL Caching Permitting Revoked Access Grants) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

OpenFGA