Relationships
Applications often grant access based on how actors and resources are connected in your domain, such as who owns a document, which organization a document belongs to, or which outside collaborators have been shared on a single file. Rather than copying role assignments onto every individual resource, record those relationships as facts and derive access across them in rules.
Deriving access from relationships
Section titled “Deriving access from relationships”Suppose members of an organization should be able to edit every document belonging to that organization. Connect the document’s parent relationship (has_relation) with the user’s organization role (has_role) by repeating a shared org: Organization variable across both conditions:
declare has_role(User, string, Organization);declare has_relation(Document, string, Organization);
has_role(user: User, "editor", document: Document) if has_relation(document, "organization", org: Organization) and has_role(user, "member", org);When using has_relation(resource, relation, related), name the relation string from the first term’s perspective: Document:handbook has "organization" Organization:acme. Because org appears in both conditions, linking a new document to Organization:acme immediately grants existing organization members the "editor" role on it.
Combining inherited roles and direct grants
Section titled “Combining inherited roles and direct grants”You can combine organization-inherited roles with one-off collaborator shares on a single document by routing both into has_permission:
declare has_permission(User, string, Document);
// Document editors can read and edithas_permission(user: User, "read", document: Document) if has_role(user, "editor", document);
has_permission(user: User, "edit", document: Document) if has_role(user, "editor", document);
allow(actor, action, resource) if has_permission(actor, action, resource);- Inherited access:
User:aliceis a"member"ofOrganization:acme, which deriveshas_role(User:alice, "editor", Document:handbook)and grants"read"and"edit". - Direct share: Inserting
has_permission(User:bob, "read", Document:handbook)grantsUser:bobread access to that single document without granting"edit"or access to other documents inOrganization:acme.
Choosing how many layers to introduce
Section titled “Choosing how many layers to introduce”Deriving an intermediate document role (has_role(user, "editor", document)) is useful when multiple rules or direct per-document role assignments also target "editor". If your product never assigns document-level roles directly, derive has_permission straight from the organization relationship:
has_permission(user: User, "edit", document: Document) if has_relation(document, "organization", org: Organization) and has_role(user, "member", org);Additive paths and revocation
Section titled “Additive paths and revocation”Stored facts and rule-derived conclusions are additive: an authorization check succeeds if any path proves allow(actor, action, resource) and no deny(actor, action, resource) matches.
If User:alice is a member of Organization:acme and also holds a direct has_permission(User:alice, "read", Document:handbook) fact, removing her organization membership stops the inherited path, but the direct has_permission fact will still allow her to "read" Document:handbook until that fact is also deleted:
// Removing organization membership stops this rule:has_role(user: User, "editor", document: Document) if has_relation(document, "organization", org: Organization) and has_role(user, "member", org);
// But this stored fact continues to allow read access:has_permission(User:alice, "read", Document:handbook);When revoking access, your application can proceed in two ways:
- Targeted grant deletion: Delete each stored fact providing an independent path to that resource as covered in Managing Facts.
- Blanket access denial: When an actor must be blocked across all resources immediately (such as during account suspension), define an optional
denyrule as shown in Designing Policies. A matchingdenyeliminates access across all additive paths without requiring you to locate and delete every individual grant upfront.
Next steps
Section titled “Next steps”- Propagate relationships across nested folder and group trees in Hierarchies & Recursion.
- Layer attribute comparisons onto relationship rules in Attributes.
- Verify relationship boundaries with the CLI in Testing & Validating Policies.