This document is a draft for implementing custom permissions in Permify for SaaS applications.

Initially, entities, permissions, and certain relationships must be predefined and should not be alterable by tenants. The system owner should be able to control all of these aspects through a single template. Tenants should not be allowed to add new permissions, remove existing ones, or create new entities. These tasks should be designed by the system administrator. Tenants should, however, be able to customize the templates within boundaries set by the system's administrator to suit their needs.

Schema Template

entity user {}

entity systemuser {}

entity system {
	relation admin @systemuser
}

entity organization {
	relation admin @user
	
	{{.Relations}}
}

entity task {

	relation organization @organization
	relation system @system
	relation owner @user
	
  {{.Relations}}
  {{.Attributes}}
  
  permission view = system.admin or ({{.Condition | default:owner}})
  permission edit = system.admin or ({{.Condition | default:owner}})
  permission delete = system.admin or ({{.Condition | default:organization.admin}})
}

In this template, the system itself represents the system. Users, customers, and system users are the administrators of the system. The developer of the system structures the template by marking customizable areas with {{}} symbols. Then, tenants can make the allowed changes as they wish, using UI components we provide.

The template is merely a schema, and new versions can be produced. Tenants' modifications are stored separately (in a different table). The reason for storing these pieces separately is to prevent changes in the main template from complicating the management of existing schemas and potentially creating security vulnerabilities. These parts are merged with the template at runtime and cached with their versions. This approach ensures the system continues to operate without performance degradation, security vulnerabilities, and without requiring difficult maintenance.

Sample Tenant X

A tenant's schema merged on the example template

entity user {}

entity systemuser {}

entity system {
	relation admin @systemuser
}

entity organization {
	relation admin @user
	
	// custom role
	relation member @user
}

entity task {

	relation organization @organization
	relation system @system
	relation owner @user
	
	// custom role
  relation assignee @user
  
  // Since the tenant does not have a specific condition for this permission,
  // the default one was assigned.
  permission view = system.admin or (owner)
  
  permission edit = system.admin or (assignee or (owner or organization.admin))
  permission delete = system.admin or (assignee or organization.admin)
}

When creating data, it will be validated according to a schema specific to the tenant. Additionally, relationships will be established through the UI. It's not necessary to segregate data for each tenant. Ensuring data uniqueness will be logical for SaaS applications.