antonello
08/28/2026, 10:37 AMAsk Inkeep
08/28/2026, 10:37 AMAsk Inkeep
08/28/2026, 10:37 AMpermit and custom, and you write your custom logic in the custom folder :
package permit.custom
default allow := false
You can then reference Permit's generated evaluation context, e.g.:
import data.permit.policies
allow {
not "rbac" in policies.__allow_sources
}
Custom rules can pull in RBAC context too:
import permit.rbac
To wire a custom package into the final decision, root.rego combines the default policies with your custom logic:
allow {
policies.allow
custom.allow
}
You aren't limited to one custom file — you can add multiple files/folders under custom and either centralize them into one root file or import multiple custom packages into root.rego .
Note: Permit.io is policy-engine agnostic and also supports AWS Cedar as an alternative to Rego if that fits your modeling style better (3) (4) .
If you have specific policies you're trying to port from XACML/ALFA, the Permit.io team explicitly offers to help model them — the documentation states you can set up a meeting with their engineering team for advanced custom policy questions (2) .Ask Inkeep
08/28/2026, 10:37 AMOr Weis
08/28/2026, 10:41 AMOr Weis
08/28/2026, 10:43 AMantonello
08/28/2026, 10:46 AMOr Weis
08/28/2026, 10:52 AMantonello
08/28/2026, 11:09 AMOr Weis
08/28/2026, 11:24 AMOr Weis
08/28/2026, 11:25 AMOr Weis
08/28/2026, 11:25 AMAsk Inkeep
08/28/2026, 11:25 AMAsk Inkeep
08/28/2026, 11:25 AMAsk Inkeep
08/28/2026, 11:25 AMOr Weis
08/28/2026, 11:26 AMAsk Inkeep
08/28/2026, 11:27 AMAsk Inkeep
08/28/2026, 11:27 AMpermit.check()) is the core enforcement component, and it considers User, Action, Resource, and Context as elements when making a decision — where Context is defined as "any additional data that might be relevant for evaluating the policy decision" (1) .
On the resource/user attribute side, the sources show attributes being passed as part of the user and resource objects rather than as a separate context parameter. For example, additional user attributes and resource attributes can be passed via the CLI's pdp check command:
$ permit pdp check --user eventHandler --action update --resource Widget:dashboard-1-widget
(2)
with optional enrichment arguments:
• --user-attributes - additional user attributes to enrich the authorization check in the format: key1=value1,key2=value2
• -resource-attributes - additional resource attributes to enrich the authorization check in the format key1=value1,key2=value2
I don't have explicit documentation showing the exact SDK-level permit.check() call signature for passing attributes/context as arguments (e.g., in Python or Node.js) beyond the CLI example above. I do have confirmation that a bug involving inconsistent handling of userAttributes and resourceAttributes between single (loadLocalState) and bulk (loadLocalStateBulk) permission checks in the frontend SDK was reported and has since been closed as fixed (3) .
If you want, I can look specifically for the SDK method signature for check() with attributes/context in a particular language (Python, Node.js, etc.) — let me know which SDK you're using.Ask Inkeep
08/28/2026, 11:27 AMOr Weis
08/28/2026, 11:27 AMAsk Inkeep
08/28/2026, 11:27 AMAsk Inkeep
08/28/2026, 11:27 AMmatch conditions
• *Policy*: the actual rules that determine whether access is allowed or denied based on roles, resources, and condition sets
For the ABAC check itself, attributes are attached to the user and resource objects at check time. From the Node.js SDK:
const permitted = permit.check(
// the user object
{
// the user key
key: "<mailto:check@permit.io|check@permit.io>",
// just-in-time attributes on the user
attributes: {
location: "England",
department: "Engineering",
},
},
// the action the user is trying to do
"action",
// Resource
{
// the type of the resource (the resource key)
type: "resource",
// just-in-time attributes on the resource
attributes: {
hasApproval: "true",
},
// the tenant the resource belong to
tenant: "tenant",
}
) ;
(2)
And the equivalent Python version:
permitted = await permit.check(
///# User Set
{
"userId": "<mailto:check@permit.io|check@permit.io>",
"attributes": {
"location": "England",
"department": "Engineering",
},
},
///# Action
"action",
///# Resource Set
{
"type": "resource",
"attributes": {
"hasApproval": "true",
},
"tenant": "tenant",
}
)
I don't have explicit documentation on the specific mechanics of referencing one variable/attribute against another (e.g., comparing a user attribute to a resource attribute) within a condition set's match logic, either through the UI or the API. If you want, I can give a general answer based on my broader knowledge instead, or you can point me to a more specific scenario to search for.
Check out these potentially useful sources: Modeling and Implementation Components , Concepts / Glossary , Running a demoAsk Inkeep
08/28/2026, 11:27 AMantonello
08/28/2026, 11:41 AMAsk Inkeep
08/28/2026, 11:41 AMAsk Inkeep
08/28/2026, 11:42 AMmatch conditions . At check time, resource attributes are passed as part of the resource object, for example in Node.js:
const permitted = permit.check(
// the user object
{
// the user key
key: "<mailto:check@permit.io|check@permit.io>",
// just-in-time attributes on the user
attributes: {
location: "England",
department: "Engineering",
},
},
// the action the user is trying to do
"action",
// Resource
{
// the type of the resource (the resource key)
type: "resource",
// just-in-time attributes on the resource
attributes: {
hasApproval: "true",
},
// the tenant the resource belong to
tenant: "tenant",
}
) ;
(3)
*ABAC checking an attribute (e.g., "owner") against the input "user key"*
The sources don't include explicit documentation on referencing one attribute against another (such as comparing a resource's "owner" attribute to the input user key) within a condition set's match logic, either via UI or API.
*Composing ReBAC + ABAC into a single checkable policy*
The Policy component itself is described as "the actual rules that determine whether access is allowed or denied based on roles, resources, and condition sets" (2) , and the Enforcement Plane's Check Function (permit.check()) evaluates User, Action, Resource, and Context together . Beyond that framing, the sources don't detail the specific Policy Editor mechanics for combining a ReBAC-derived role condition with ABAC attribute conditions into one policy rule.
Given these gaps, I don't have enough documented detail to walk you through the exact Policy Editor steps for the attribute-to-user-key comparison or the combined rule composition. I can give a general answer based on broader knowledge if you'd like — otherwise, this looks like a good candidate for the enterprise form or a direct question to the team, since it touches on Policy Editor UI mechanics not covered in these sources.
Check out these potentially useful sources: Modeling and Implementation Components , What is Relationship-Based Access Control (ReBAC) ? , Attribute-Based Access Control (ABAC) VS. Relationship-Based Access Control (ReBAC) Ask Inkeep
08/28/2026, 11:42 AMOr Weis
08/28/2026, 11:43 AMAsk Inkeep
08/28/2026, 11:43 AMAsk Inkeep
08/28/2026, 11:43 AMPlan declares a parent relation to `account`:
await permit.api.resources.create({
key: "plan",
name: "Plan",
...
relations: {
parent: "account",
},
}) ;
(1)
*Roles with permissions and derivations*
A resource-level role (like editor on plan) can declare granted_to logic that derives the role from another resource's role, using the relation declared above:
await permit.api.resources.create({
key: "plan",
name: "Plan",
...
roles: {
editor: {
name: "Editor",
permissions: ["view", "change"],
granted_to: {
users_with_role: [
{
role: "editor",
on_resource: "account",
linked_by_relation: "parent",
},
],
},
},
},
...
}) ;
This ties the parent relation directly to a role derivation: Account#Editor → Plan#Editor .
*Condition sets for ABAC (user sets and resource sets) *
Condition sets are created separately via conditionSets.create, specifying type: "userset" or type: "resourceset" and the attribute-based conditions:
await permit.api.conditionSets.create({
key: "blocked_users",
name: "Blocked Users",
type: "userset",
conditions: {
allOf: [{ allOf: [{ "user.blocked": { equals: true } }] }],
},
}) ;
await permit.api.conditionSets.create({
key: "owned_plans",
name: "Owned Plans",
type: "resourceset",
resource_id: "plan",
conditions: {
allOf: [
{ allOf: [{ "resource.owner": { equals: { ref: "user.key" } } }] },
],
},
}) ;
This resource set shows an attribute-to-input comparison — resource.owner matched against { ref: "user.key" }, i.e. referencing the value passed in as the user key at check time .
*Connecting condition sets into a policy rule*
The conditionSetRules.create call is what ties a user set and a resource set together into an enforceable permission:
await permit.api.conditionSetRules.create({
user_set: "active_users",
resource_set: "owned_plans",
permission: "plan:view",
}) ;
await permit.api.conditionSetRules.create({
user_set: "active_users",
resource_set: "owned_plans",
permission: "plan:change",
}) ;
*Enforcement*
All of the above (relations, role derivations, condition sets, and condition set rules) feed into the single permit.check() call, which takes user, action, and resource and evaluates against everything configured:
export const authorize = async (user, action, resource) => {
return permit.check(user, action, resource) ;
};
So in API terms: resources.create defines relations → role `granted_to`/`linked_by_relation` derives ReBAC permissions across those relations → conditionSets.create defines ABAC user/resource attribute matches (including matching an attribute like owner against the input user.key) → conditionSetRules.create binds a user_set + resource_set to a specific permission → permit.check() evaluates it all together .
I don't have documentation showing how to combine a role-derivation (ReBAC) condition and a condition-set (ABAC) rule within the _same_ single rule object — the source only shows them as separate constructs (roles.granted_to vs conditionSetRules) that both ultimately feed the same permit.check() call .Ask Inkeep
08/28/2026, 11:43 AM