Extending Authorization Models
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
The authorization system in MuteTaxes is built on a Relationship-Based Access Control (ReBAC) paradigm using OpenFGA. It provides a flexible mechanism to define, manage, and enforce fine-grained permissions across various system resources, referred to as "tables" (e.g., clients, invoices). The core purpose of this model is to decouple authorization logic from the application code, allowing for complex relationship definitions—such as role memberships and resource-specific badges—to be evaluated dynamically.
By extending this model, administrators can configure a permission matrix that maps roles to specific CRUD actions (Create, Read, Update, Delete) on resources. The system bridges a relational database (PostgreSQL via Prisma), which stores entity metadata, with OpenFGA, which serves as the "source of truth" for relationship tuples and authorization checks.
Sources: PLAN.md:3-10, backend/src/fga/fgaClient.ts:1-20
Core Authorization Model Structure
The system utilizes a Domain Specific Language (DSL) to define types and relations. The model is structured around three primary entity types: user, role, and table. Relationships are established through "tuples" stored in OpenFGA.
Type Definitions and Relations
The authorization model defines how subjects (users or roles) relate to objects (tables).
| Type | Relation | Definition / Allowed Types |
|---|---|---|
| user | N/A | Base entity representing a person. |
| role | member | A collection of users: [user] |
| table | creator | Users or members of a role: [user, role#member] |
| table | reader | Users or members of a role: [user, role#member] |
| table | updater | Users or members of a role: [user, role#member] |
| table | deleter | Users or members of a role: [user, role#member] |
The model further defines "computed relations" for permission checks, such as can_read, which evaluates if a user satisfies any of the base relations (e.g., reader or creator).
Sources: PLAN.md:25-45, backend/src/fga/fgaClient.ts:31-35
Relationship Hierarchy Flow
The following diagram illustrates how a user gains access to a table resource through role membership.
Backend Integration and API Logic
The backend integrates with OpenFGA using an official SDK wrapper. This wrapper handles model initialization, permission checks, and tuple management.
FGA Client Operations
The fgaClient.ts provides high-level functions to interact with the OpenFGA server:
- Permission Checking:
checkPermission(userId, tableSlug, action)verifies if a user can performcan_create,can_read, etc. - Role Management:
assignRoleToUserandremoveRoleFromUsermanage membership tuples in the formrole:<roleName>#member@user:<userId>. - Badge Management:
grantCrudBadgeToRoleandrevokeCrudBadgeFromRoleassign specific capabilities (creator, reader, etc.) to a role for a specific table.
Sources: backend/src/fga/fgaClient.ts:101-118, backend/src/fga/fgaClient.ts:187-210
Permission Matrix Management
The system exposes a permission matrix to Super Admins, allowing for bulk updates of authorization tuples.
Middleware and Access Enforcement
Access control is enforced at the route level using middleware. The authorizeTable middleware intercepts requests and performs a live check against OpenFGA before allowing the request to proceed to the controller.
Authorization Middleware Variants
| Middleware | Parameters | Description |
|---|---|---|
authorizeTable | action, tableSlug | Checks a specific action against a hardcoded table slug. |
authorizeTableFromParam | action, paramName | Checks an action against a table slug provided in the URL parameters (default :table). |
Sources: backend/src/middleware/authorizeTable.ts:5-30
Data Flow for Request Authorization
Dynamic Model Resolution
To ensure the system is always running against a valid authorization model, the backend includes logic to automatically resolve or upload the authorization model DSL from the infra/openfga/model.fga file.
- Initialization: Upon start, the system checks if a model with types
role,table, anduserexists in the OpenFGA store. - Auto-Migration: If no valid model is found, the system reads the local
.fgafile, transforms the DSL to JSON, and writes a new authorization model to OpenFGA.
Sources: backend/src/fga/fgaClient.ts:44-89
Summary
Extending the authorization model in this system involves defining new relationships in the OpenFGA DSL and managing those relationships via the backend API. By utilizing roles as intermediaries between users and resources (tables), the system achieves a scalable and audit-able access control layer. The integration of Prisma for metadata and OpenFGA for relationship logic allows the UI to dynamically adapt based on real-time permission checks, such as filtering the sidebar or disabling action buttons.
Sources: PLAN.md:12-23, backend/src/modules/me/me.routes.ts:11-40