Hi <Permit.io> Team, I’d like to ask for your reco...
# permit-saas
m
Hi Permit.io Team, I’d like to ask for your recommendation on how to best handle field-level or field-group-level authorization in Permit.io. Specifically, how would you model something like this hierarchy: • Car → has an Engine • Engine → has multiple Parts (each part may have different permissions) I saw that Oso has a concept of field-level authorization (docs link ), and I’m wondering what’s the recommended approach in Permit.io for a similar use case. Would you suggest: 1. Creating a separate
resource_type
for each level (e.g.,
car
,
engine
,
engine_part
), 2. Or using some other pattern (like nested attributes, resource instances, or metadata-based policies)? My main concern is scalability — if each car has many parts, then modeling each part as a separate resource type could lead to a very large and complex model. How would you recommend approaching this problem in Permit.io?
a
Hi @Michał Wójcik, I'm an AI assistant for Permit.io. I'll analyze available sources and get back to you shortly.
For field-level or component-level authorization in Permit.io, I recommend using *ReBAC (Relationship-Based Access Control) * with resource types and relations to model your hierarchy (1) . This approach handles nested structures elegantly while maintaining scalability. Recommended Approach: ReBAC with Relations Create separate resource types for each level (
car
,
engine
,
engine_part
) and connect them using ​*relations*​ . This is similar to how Google Drive models folders containing files . Here's how to model your Car → Engine → Parts hierarchy: 1. Define Resources with Relations
Copy code
await permit.api.create_resource(
    {
        "key": "engine_part",
        "name": "Engine Part",
        "actions": {
            "read": {},
            "update": {},
            "replace": {}
        },
        "roles": {
            "maintainer": {
                "name": "Maintainer",
                "permissions": ["read", "update", "replace"]
            },
            "viewer": {
                "name": "Viewer",
                "permissions": ["read"]
            }
        }
    }
)
Copy code
await permit.api.create_resource(
    {
        "key": "engine",
        "name": "Engine",
        "actions": {
            "read": {},
            "service": {},
            "modify": {}
        },
        "roles": {
            "engineer": {
                "name": "Engineer",
                "permissions": ["read", "service", "modify"]
            },
            "inspector": {
                "name": "Inspector",
                "permissions": ["read"]
            }
        }
    }
)
2. Create Relations Between Resources
Copy code
await permit.api.resource_relations.create(
    "engine_part",
    {
        "key": "parent",
        "name": "Parent",
        "subject_resource": "engine",
    }
)
Copy code
await permit.api.resource_relations.create(
    "engine",
    {
        "key": "parent",
        "name": "Parent",
        "subject_resource": "car",
    }
)
3. Enable Permission Inheritance Configure roles to inherit permissions through the parent relationship :
Copy code
await permit.api.resource_roles.update(
    "engine_part",
    "maintainer",
    {
        "granted_to": {
            "users_with_role": [
                {
                    "linked_by_relation": "parent",
                    "on_resource": "engine",
                    "role": "engineer",
                }
            ]
        }
    }
)
Why This Approach Works 1. ​*Scalability*​: Relations define the structure once; you then create relationship tuples between instances . This scales better than creating unique resource types for each part. 2. ​*Hierarchical Permissions*​: Users with
engineer
role on an engine automatically get appropriate permissions on all its parts . 3. ​*Fine-Grained Control*​: You can still assign direct permissions to specific parts when needed . 4. ​*Resource Instances*​: Each car, engine, and part becomes a resource instance :
Copy code
await permit.api.resource_instances.create(
    {
        "resource": "engine_part",
        "key": "spark_plug_123",
        "tenant": "default",
    }
)
This ReBAC approach mirrors how Google Drive handles folder-level access granting permissions to contained files , making it ideal for your hierarchical authorization needs.
To learn more, see the sources I considered: [[1] Modeling Google Drive Permissions with ReBAC](https://docs.permit.io/modeling/google-drive)
o
audio_clip_2025-10-07_13-03-29-969.m4a
t
@Michał Wójcik I'd also note that Permit has the ability to combine ReBAC and ABAC. Any relationship you create with a ReBAC resource can be used to evaluate a regular ReBAC rule or you can use ReBAC resource attributes to evaluate ABAC or use them to evaluate a ABAC + ReBAC together. Our aim is to decouple business logic and policy logic and, wherever possible, standardize on the permission check(user, action, resource) call.