ABAC condition operators
This reference lists every operator you can use in the conditions of an attribute-based access control (ABAC) condition set created through the Permit API. It is for developers who write condition JSON by hand. For how the pieces fit together, see the ABAC API overview.
A condition uses two kinds of operators:
- Logical operators combine conditions:
allOf,anyOf, andnot. - Comparison operators test one attribute against a value:
equals,in,greater-than, and others.
Logical operators
Logical operators combine several conditions into one boolean result. The allOf and anyOf operators take an array of conditions. The not operator takes a single nested condition or operator, not an array.
| Logical operator | Key in the condition | Alternative key | Result |
|---|---|---|---|
| AND | allOf | and | true when every condition in the array is true |
| OR | anyOf | or | true when at least one condition in the array is true |
| NOT | not | none | true when the nested condition is false |
Comparison operators
A comparison operator object holds exactly one operator key and its operand, for example {"greater-than": 18}. To apply two comparisons to one attribute, combine them with a logical operator.
| Operator | Key in the condition | Result is true when | Operand type |
|---|---|---|---|
| Equals | equals | a = b | Bool, Number, String |
| Does not equal | not-equals | a != b | Bool, Number, String |
| Less than | less-than | a < b | Number or ISO 8601 date |
| Greater than | greater-than | a > b | Number or ISO 8601 date |
| Less than or equal | less-than-equals | a ≤ b | Number or ISO 8601 date |
| Greater than or equal | greater-than-equals | a ≥ b | Number or ISO 8601 date |
| In | in | the attribute value is one of the values in the operand array | Array |
| Between | between | the attribute value is between a lower bound and an upper bound | Array of exactly two numbers |
| Contains | contains | the string attribute contains the operand string, for example "aaa??bbbbbb" contains "??" | String |
| Matches | match | the attribute value matches a glob pattern | String (glob) |
| Array contains | array_contains | the array attribute contains the operand, for example ["a", "b", "c"] contains "a" | Array attribute |
| Array subset | array_subset | every item of the array attribute is in the operand, for example ["a", "b"] is a subset of ["a", "b", "c"] | Array |
| Array superset | array_superset | the array attribute contains every item of the operand, for example ["a", "b", "c"] is a superset of ["a", "b"] | Array |
| Array intersect | array_intersect | the array attribute and the operand share at least one value, for example ["a", "b", "c"] and ["c", "d", "e"] | Array |
| Array length equals | array_len_equals | the array attribute has exactly the operand number of items | Number |
| Array length greater than | array_len_greater_than | the array attribute has more items than the operand | Number |
| Array length less than | array_len_less_than | the array attribute has fewer items than the operand | Number |
Compare two attributes with a reference
To compare an attribute with another attribute instead of a fixed value, pass a reference object {"ref": "<object>.<attribute>"} as the operand. The reference is resolved when the policy decision point (PDP) evaluates the check.
| Comparison with a reference | Example | Attribute type |
|---|---|---|
| Equals | resource owner equals the user email | Number, Array, String |
| Does not equal | resource owner does not equal the user key | Number, Array, String |
| Contains | tenant name contains the user first_name | String |
| Array contains | ["admin", "editor"] contains the user role | Array |
| Less than | a < user.age | Number |
| Greater than | a > user.age | Number |
| Less than or equal | a ≤ user.age | Number |
| Greater than or equal | a ≥ user.age | Number |
The following condition is true when the user's email contains the user's first name. The contains operator receives {"ref": "user.first_name"} as its operand.
{
"allOf": [
{
"user.email": {
"contains": {
"ref": "user.first_name"
}
}
}
]
}
Object match operators
Object match operators run several comparisons on the fields of an attribute of type Object or Object Array. Use them when an attribute stores a dictionary, or an array of dictionaries, in the same shape as your source data.
Match the fields of an Object attribute
Suppose the user attribute user.organization has type Object and holds this value:
{
"name": "Cool Inc",
"country": "US",
"subscription": "pro",
...
}
You want a user set of users whose organization is located in the US and has a pro subscription.
If you store each field as a separate Permit attribute, standard comparison operators are enough:
{
"allOf": [
{"user.country": {"equals": "US"}},
{"user.subscription": {"equals": "pro"}}
]
}
With a single user.organization attribute of type Object, use object_match:
{
"allOf": [
{
"user.organization": {
"object_match": {
"match": {
"country": {"equals": "US"},
"subscription": {"equals": "pro"}
}
}
}
}
]
}
Inside the match object, apply one comparison operator to each field. The object_match operator returns true only when every field comparison is true.
Object attributes keep your data close to its source format. Use any_match or all_match when the attribute is an array of objects, because an array can't be split into separate attributes.
Match the items of an Object Array attribute
Suppose the user attribute user.organizations has type Object Array, because a user can belong to several organizations:
[
{
"name": "Cool Inc",
"country": "US",
"subscription": "pro",
...
},
{
"name": "Awesome Inc",
"country": "IN",
"subscription": "enterprise",
...
},
{
"name": "Sweet Inc",
"country": "US",
"subscription": "enterprise",
...
}
]
To match users with at least one organization located in the US with a pro subscription, use any_match. The match object applies to each item of the array:
{
"allOf": [
{
"user.organizations": {
"any_match": {
"match": {
"country": {"equals": "US"},
"subscription": {"equals": "pro"}
}
}
}
}
]
}
The any_match condition is true when at least one item in user.organizations has country equal to "US" and subscription equal to "pro".
To require that every item in the array matches, replace any_match with all_match:
{
"allOf": [
{
"user.organizations": {
"all_match": {
"match": {
"country": {"equals": "US"},
"subscription": {"equals": "pro"}
}
}
}
}
]
}
Object match operator reference
| Operator | Key in the condition | Result is true when | Attribute type |
|---|---|---|---|
| Object match | object_match | every field condition in match is true for the object | Object |
| Any match | any_match | every field condition in match is true for at least one item of the array | Object Array |
| All match | all_match | every field condition in match is true for all items of the array | Object Array |
Match a resource referenced by a foreign key
A resource attribute can store the key of another resource, like a foreign key in a database. For example, the repo resource has a string attribute organization that holds the key of an organization resource.
To test the attributes of the referenced resource, add fk_resource_type to the object_match operand and set it to the referenced resource type. Permit reads the attributes stored for that resource instance and applies the match conditions to them. The following condition is true when the repository's organization is located in the US:
{
"allOf": [
{
"resource.organization": {
"object_match": {
"match": {
"country": {"equals": "US"}
},
"fk_resource_type": "organization"
}
}
}
]
}
The any_match and all_match operators accept fk_resource_type for attributes that hold an array of keys. For example, the repo resource has an attribute issues (array of strings) that holds the keys of its issue resource instances. The following condition is true when every issue of the repository is closed:
{
"allOf": [
{
"resource.issues": {
"all_match": {
"match": {
"status": {"equals": "closed"}
},
"fk_resource_type": "issue"
}
}
}
]
}
The following condition uses any_match and is true when at least one issue of the repository is not closed:
{
"allOf": [
{
"resource.issues": {
"any_match": {
"match": {
"status": {"not-equals": "closed"}
},
"fk_resource_type": "issue"
}
}
}
]
}
Other ABAC operators can use attributes passed in the permit.check() call or attributes stored in Permit. A foreign key condition reads the referenced resource's attributes from the resource instance stored in Permit, so the check call doesn't need to pass them.
Next steps
- Build conditions by nesting logical and comparison operators.
- Create condition sets that use these conditions.