Public and Private Resources
The simplest ABAC pattern uses a single boolean attribute to toggle a resource between public (visible to anyone) and private (visible only to the owner).entity user {}
entity resource {
relation owner @user
attribute is_public boolean
permission view = is_public or owner
permission edit = owner
}
How it works
view — granted if is_public is true or the subject is the owner.
edit — granted only to the owner, regardless of visibility.
When is_public is false (or not set), only the owner can view the resource.Writing the attribute
Set the attribute value when creating or updating a resource using the data write API:{
"tenant_id": "t1",
"metadata": {
"schema_version": ""
},
"attributes": [
{
"entity": {
"type": "resource",
"id": "1"
},
"attribute": "is_public",
"value": {
"@type": "type.googleapis.com/base.v1.BooleanValue",
"data": true
}
}
]
}
This pattern works well for social platforms where posts can be restricted to followers only based on a boolean is_public attribute.
Text and Object-Based Conditions
String attributes are useful when access control depends on text values such as location, device type, time zone, or day of week. A rule checks whether the incoming context matches the allowed values.Location-based access
entity user {}
entity organization {
relation admin @user
attribute location string[]
permission view = check_location(location) or admin
}
rule check_location(location string[]) {
context.data.current_location in location
}
location is a string[] attribute storing allowed locations for the organization (e.g. ["USA", "EU"]).
context.data.current_location is a dynamic value sent with each permission check request.
- Admins bypass the location check entirely.
Weekday-only repository access
In this example a repository can only be viewed on valid weekdays, and the user must also be a member of the organization.This schema requires Permify v1.1 or later.
entity user {}
entity organization {
relation member @user
attribute valid_weekdays string[]
permission view = is_weekday(valid_weekdays) and member
}
entity repository {
relation organization @organization
permission view = organization.view
}
rule is_weekday(valid_weekdays string[]) {
context.data.day_of_week in valid_weekdays
}
How it works
- The
valid_weekdays attribute stores allowed days (e.g. ["Monday","Tuesday","Wednesday","Thursday","Friday"]).
context.data.day_of_week carries the current day sent at check time.
- Both
is_weekday and the member relation must be true to grant view access.
repository.view simply delegates to organization.view, inheriting the rule transparently.
Example relationships and check trace:organization:1#member@user:1
| Sub-query | Result |
|---|
organization:1$is_weekday(valid_weekdays) (day = “Monday”) | true |
organization:1#member@user:1 | true |
repository:42#view@user:1 | Allow |
Numerical Conditions
Integer and double attributes are ideal for age gates, security clearance levels, balance checks, and any threshold-based rule.Integer — Age Restriction
entity content {
permission view = check_age(request.age)
}
rule check_age(age integer) {
age >= 18
}
request.age is provided in context.data at check time. If the attribute is not set, Permify defaults integers to 0.If you don’t write an integer attribute for an entity, Permify treats it as 0.
Double — Credit / Balance Check
entity user {}
entity account {
relation owner @user
attribute balance double
permission withdraw = check_balance(request.amount, balance) and owner
}
rule check_balance(amount double, balance double) {
(balance >= amount) && (amount <= 5000)
}
balance is stored on the account entity. request.amount is passed dynamically at check time.If you don’t write a double attribute for an entity, Permify treats it as 0.0.
Banking Withdrawal — Full Example
This model enforces two conditions before a withdrawal is allowed:
- The requester must be the account owner.
- The requested amount must be ≤ the current balance and ≤ 5 000.
entity user {}
entity account {
relation owner @user
attribute balance double
permission withdraw = check_balance(request.amount, balance) and owner
}
rule check_balance(amount double, balance double) {
(balance >= amount) && (amount <= 5000)
}
Relationships and attributes:account:1#owner@user:1
account:1$balance|double:4000
Check trace for Can user:1 withdraw from account:1 with amount = 3000:| Sub-query | Result |
|---|
account:1$check_balance(context.amount, balance) (3000 ≤ 4000 and ≤ 5000) | true |
account:1#owner@user:1 | true |
account:1#withdraw@user:1 | Allow |
Combine numerical attribute checks with hierarchical ReBAC patterns for complex financial authorization scenarios such as budget approvals and spending limits.