Authorization
CRAFT uses OpenFGA for authorization, implementing Relationship-Based Access Control (ReBAC). Unlike traditional RBAC where roles grant flat permission sets, ReBAC models permissions as relationships between users and resources, enabling fine-grained, hierarchical access control.OpenFGA is the open-source implementation of Google’s Zanzibar authorization system. It evaluates permission checks in single-digit milliseconds, making it suitable for per-request authorization in API endpoints.
Core Concepts
Relationship Tuples
Relationship Tuples
A relationship tuple is the fundamental building block. It states: “This user/group has this relation on this resource.”Tuples are stored in OpenFGA and queried during permission checks.
Resource Types
Resource Types
The authorization model defines types for every resource in the platform:
Relations (Roles)
Relations (Roles)
Relations represent the roles a user or group can have on a resource:
Computed Permissions
Computed Permissions
Computed permissions are derived from relations using OR logic. For example, The full set of computed permissions:
can_read is granted to anyone with viewer, operator, developer, admin, or owner relation:Permission Inheritance
The authorization model uses OpenFGA’sfrom keyword to implement hierarchical permission inheritance:
admin automatically has appropriate access to all projects and resources within their organization, without needing explicit tuples on each resource:
Computed delegation: can_delete from project
For resource types like data_connection, the schema computes resource-level permissions from project-level permissions. For example, can_delete on a data connection is satisfied if the user has delete rights on the parent project:
can_delete on every project (via the org-from-project chain above) can also delete every project-scoped resource without per-resource tuples.
Service worker permissions on data_connection
Service workers (background tasks like the data-readiness worker, scheduled enrichment runs, and dataset sync jobs) need to invoke data connections. The schema grants can_execute on data_connection to the service-worker role at the project level so workers can POST /assets/data/{resource_uri}/verify and GET /assets/data/{resource_uri}/secret against any connection in their assigned project, without needing a per-connection tuple.
This follows the same pattern as can_create_resources on project for service workers: a single role binding at the parent grants narrow operational permissions across all child resources.
Authorization Schema (OpenFGA DSL)
The schema is defined inopenfga-schema.fga and compiled to openfga-schema.json for runtime use. Here is a simplified excerpt showing the project type:
The require_permission Pattern
All API endpoints use therequire_permission() dependency to enforce authorization. This is implemented in the shared common package and used consistently across all services:
Permission Check Flow
Whenrequire_permission() is invoked, the following occurs:
1
Extract Resource ID
The resource ID is resolved from path parameters, query parameters, or headers based on the configuration.
2
Get Auth Context
The
Auth object is extracted from the validated JWT, providing sub (user ID) and teams (group memberships).3
Check OpenFGA
The permission checker queries OpenFGA with:
- User:
user:{sub}and eachgroup:{group_name}#member - Relation: The computed permission (e.g.,
can_delete) - Object:
{resource_type}:{resource_id}
true, access is granted.4
Return Result
- 200/success: Permission granted, the endpoint handler executes
- 403 Forbidden: Permission denied, the request is rejected
- 500 Internal Server Error: Permission system misconfigured
Permission API
The Governance service exposes a Permissions API for programmatic permission management:Keycloak Groups and OpenFGA
The bridge between Keycloak (identity) and OpenFGA (authorization) is Keycloak groups:- Users are assigned to groups in Keycloak (e.g.,
org-admins,project-developers) - A groups mapper on the realm ensures group memberships appear in the JWT
groupsclaim - During bootstrap, permission tuples map groups to OpenFGA relations (e.g.,
group:org-admins#member->adminonorganization) - At runtime,
require_permission()checks both the user’s direct tuples and their group-based tuples
Next Steps
Authentication
Understand how JWT tokens carry group claims for authorization.
Organizations
See how organization-level permissions are bootstrapped.
Projects
Learn about project-level role assignments and inheritance.
Multi-Tenancy
Explore the full tenant isolation architecture.

