Permify Schema
Permify has its own language that you can model your authorization logic with. The language allows you to define arbitrary relations between users and objects. You can assign users associate them with arbitrary objects representing application concepts, such as teams, organizations, or stores. You can give users roles such as admin, manager, or member. You can also use dynamic attributes in your authorization model, such as boolean variables, IP range, or time period.
You can define your entities, relations between them and access control decisions using the Permify Schema language. It includes set-algebraic operators such as intersection and union. These allow you to specify complex access control policies in terms of user-object relations.
Here’s a simple breakdown of our schema.
Permify Schema can be created on our playground as well as in any IDE or text editor. We also have a VS Code extension to ease modeling Permify Schema with code snippets and syntax highlights. Note that on VS code the file with extension is “.perm”.
Developing a Schema
This guide will show how to develop a Permify Schema from scratch with an example. It’s relatively simple, yet it will illustrate almost every aspect of the modeling language. We’ll follow a simplified version of the GitHub access control system, where teams and organizations have control over the viewing, editing, or deleting access rights for their repositories. Before we start, here’s the full implementation of the simplified Github access control example using Permify Schema.You can start developing Permify Schema on VSCode. You can install the extension by searching for Perm in the extensions marketplace.
Defining Entities
The first step to building Permify Schema is creating entities. An entity is an object that defines your resources which hold roles in your permission system. Think of entities as tables in your database. It is strongly recommended to name entities the same as the corresponding database table name. Doing so allows you to model and reason about your authorization and eliminate the possibility of error. You can create entities using theentity keyword. Let’s create some entities for our example GitHub authorization logic.
- relations: how entities relate to each other
- actions or permissions: what can be allowed or denied
- attributes: properties of an entity not related to other entities
Defining Relations
Relations represent relationships between entities. It’s the most critical part of the schema because Permify is based on relations between resources and their permissions. Use the keywordrelation to create an entity relation with the name and type properties.
Relation Attributes:
- name: the name of the relation, may contain only letters and underscores and must be at most 64 characters long
- type: the target entity type this relation references (e.g. user, organization, document), which must exist in the schema
User Entity
→ The user entity is a mandatory entity in Permify. It generally will be empty, but it will be used in other entities as a relation type referencing users.Roles and User Types
You can define user types and roles within an entity. If you want a global role, such asadmin, define it at the entity highest in the global hierarchy, such as an organization. Then, share it with the rest of the entities by including it within permissions.
For the sake of simplicity, let’s define only two user types in our organization: administrators and members of the organization.
Parent-Child Relationship
→ Let’s say teams can belong to organizations and can have members. We model that as follows:Ownership
In the simple GitHub example we are following, organizations and users can have multiple repositories. Each repository is related with an organization and with users. The repository entity is defined as follows:Multiple Relation Types
You may have noticed new syntax above:user or that this user must be a team member.
You can use # character to reach an entity’s relation. When you define the relation like this, you can only add users directly as tuples. (You will learn about tuples in the next section.) For example:You then can specify not only individual users but also members of an organization as a tuple:
@team#member specifies that if the user has a relation with the team, this relation must be a member relation. This is called feature locking, because it locks the relation type to that of the prefixed entity. No other relation on @team will be allowed.Feature locking allows you to specify sets of assigned users.For example:- organization:1#viewer@user:U1
- organization:1#viewer@user:U2
@user and @organization#member :- organization:1#viewer@user:U1
- organization:1#viewer@user:U2
- organization:1#viewer@organization:O1#member
organization:1#viewer@organization:O1#member, all members of the organization O1 will have the right to perform the defined action. In this case, all members in O1 now have the viewer relation.These definitions prevent you from creating undesired user set relationships.Defining Permissions
Actions describe what relations, or a relation’s relation can do. They are permissions of the entity to which the action belongs. Actions define who can perform a specific action on an entity, and in which circumstances. The basic form of an authorization check in Permify is Can the user U perform action X on a resource Y ?. The keywords action or permission are equivalent.Intersection and Exclusion
The Permify Schema supportsand, or and not operators. These offer you permission intersection and exclusion. You can use these in combination with actions to define complex authorization logic.
Intersection
Let’s get back to our GitHub example and create a read action on the repository entity to show an example of theand and or operators.
delete action, you can see the permission is limited to a user that is an organization admin and also has one of the following relations: owner of the repository, or maintainer, or member of the organization which repository belongs to.
The same Using the
delete action can also be defined using the permission keyword, as follows:action or permission keywords yields the same authorization logic. We have two keywords for defining a permission because most, but not all, permissions are based on actions. Learn more in our Nested Hierarchies section.and operation creates an intersection between relations but is not tied to specific entities. For example, in the following model, users can see a repository if they are a member or admin of any organization.
Let’s say user:1 is a member of organization:1 and an admin of organization:2. If repository:1 belongs to organization:1, then user:1 has access to delete repository:1.
Exclusion
We’ll now move beyond the GitHub example and explore more advanced abilities of the Permify Schema. Let’s examine thenot operator.
Here is the post entity from our sample Instagram Authorization Structure example,
restricted attribute won’t be able to like or comment on the specific post. More details about defining attributes can be found in the Attribute Based Permissions (ABAC) section.
With the not operator, you can exclude users, resources, or any subject from permissions.
Permission Union
Permify allows you to set permissions that are the union of multiple permission sets. You can define permissions as relations. You can use actions (or permissions) when defining another action (or permission):delete action inherits from the edit action. Both organization administrators and any relation capable of performing the edit action (in this case, a member or manager) can also perform the delete action.
Creating permission unions is beneficial when a user needs to have access across different departments or roles.
Let’s examine our modeling guides for common permission use cases.
Attribute Based Permissions (ABAC)
To support Attribute Based Access Control (ABAC), there are two additional components in our schema language:attribute and rule.
Defining Attributes
Attributes define properties for entities with specific data types. For instance, an attribute could be an IP range associated with an organization, defined as a string array:attribute.
Defining Rules
Rules allow you to write conditions for the model. These are similar to functions that every software language has. They accept parameters and, based on conditions, return either a true or a false value. In the following example schema, thecheck_ip_range rule checks if a given IP address falls within a specified IP range:
We designed our schema language based on Common Expression Language (CEL). The syntax looks nearly identical to equivalent expressions in C++, Go, Java, and TypeScript.Please let us know via our Discord channel if you have questions regarding syntax, definitions or any operator you identify not working as expected.
Modeling Guides
Our modeling guides offer specific examples of common permission use cases. Role-Based Access Control (RBAC) Relationship Based Access Control (ReBAC) Attribute Based Access Control (ABAC)More Comprehensive Examples
You can also check out comprehensive schema examples from the Real World Examples section. Here is what each example focuses on,- Google Docs: how users can gain direct access to a document through organizational roles or through inherited/nested permissions.
- Facebook Groups: how users can perform various actions based on the roles and permissions within the groups to which they belong.
- Notion: how one global entity (workspace) can manage access rights in the child entities that belong to it.
- Instagram: how public/private attributes can play a role in granting access to specific users.
- Mercury: how attributes and rules interact within the hierarchical relationships.