Casbin Authorization Policies Documentation

10 min read

This page explains how authorization policies work on the Unique platform: how a policy rule is structured, what every field means, which resources and actions exist, and how to create custom policies via the API.

Authorization on the platform is handled by the Gatekeeper service, which uses Casbin as its policy engine. Every permission check and every policy you create ultimately maps to a Casbin rule.

Authorization model

Every authorization check answers one question:

May subject (a user, role, or group) from company perform action on resource, where the object belongs to object company and is owned by object owner?

The formal Casbin model (from next/services/gatekeeper/src/casbin/model.conf) defines six request fields and seven policy fields:

ini
[request_definition]
r = sub, dom, obj, obj_company, obj_owner, act

[policy_definition]
p = sub, dom, obj, obj_company, obj_owner, act, eft

[role_definition]
g = _, _, _
g2 = _, _, _

[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))

Two properties of this model are important to understand before writing policies:

  1. Allow unless denied. A request is granted when at least one matching policy has effect allow and no matching policy has effect deny. A single deny rule overrides any number of allow rules. This makes deny rules a powerful tool for carving exceptions out of broad grants and a dangerous one if applied too widely.

  2. Role inheritance. A policy whose subject is a role (e.g. Chat_User) applies to every user assigned to that role via a g rule, including transitively through role-to-role and group-to-group inheritance.

Evaluation flow for a single request:

casbin-policy-evaluation.png

eft is Casbin's abbreviation for effect the outcome a policy rule produces when it matches a request. In this model it's the last field of a p rule (stored in column v6), and it takes one of two values:

  • allow the rule grants the access it describes

  • deny the rule blocks the access it describes

The policy effect line in the model config defines how effects from all matching rules combine:

How policies are stored: ptype and v0v6

Policies are persisted in the casbin_rule database table. Casbin uses a generic column layout ptype plus positional columns v0 through v6 and the meaning of each column depends on the ptype of the row.

ptype values

ptype

Name

Purpose

Who writes it

p

Permission policy

Grants or denies an action on a resource to a subject

Platform (role defaults), admins via API

g

Grouping policy

Assigns a member to a role or group: user → role, user → group, group → parent group, group → role

Platform (IdP sync, group sync), admins via API

g2

Same-group relationship

Records that two users share a group; used only to evaluate ownGroup policies

System-managed only never create these manually

Field reference for p rules (permission policies)

For a p row, the columns map to the policy definition p = sub, dom, obj, obj_company, obj_owner, act, eft:

Column

Casbin field

Meaning

Example values

v0

sub

Subject who the policy applies to: a user ID, a role ID, or a group (group_{id})

subject:usr_abc123, subject:Chat_User, subject:group_xyz

v1

dom

Subject's company (domain) the tenant in which the policy applies

company:cmp_abc123, company:*

v2

obj

Resource what the policy is about (see Resources); may be instance-scoped

resource:chat, resource:assistant:asst_xyz, resource:*

v3

obj_company

Object's company which tenant the accessed object must belong to

company:own, company:cmp_abc123, company:*

v4

obj_owner

Object owner who must own the accessed object

subject:own, subject:ownGroup, subject:usr_abc123, subject:*

v5

act

Action the operation being permitted or denied (see Actions)

action:read, action:write, action:manage

v6

eft

Effect allow or deny

allow, deny

The distinction between v1 (subject's company) and v3 (object's company) exists so cross-tenant access can be expressed explicitly. In practice, almost all customer policies use company:own for v3, meaning "the object must belong to the same company as the requesting user".

Field reference for g rules (role and group assignments)

For a g row, the columns map to g = member, role_or_group, company:

Column

Meaning

Example values

v0

Member the user or group being assigned

subject:usr_abc123, subject:group_child

v1

Role or parent group what the member is assigned to

subject:Chat_User, subject:custom__my_role, subject:group_parent

v2

Company (domain) the tenant in which the assignment applies

company:cmp_abc123

A g rule means: within v2, subject v0 inherits everything granted to v1. Role assignments are transitive if a user is in a group, the group inherits a role, and that role inherits another role, the user gets all of it.

g2 rules (system-managed)

g2 rows record that two users share at least one group (v0 = requesting user, v1 = object owner, v2 = company). They exist solely so that policies with objectOwner = ownGroup can be evaluated, are generated on demand by the platform, and are invalidated when group membership changes. Never create or delete g2 rows yourself.

Value prefixes

Values in the casbin_rule table carry a URN-style prefix identifying what kind of value they are:

Prefix

Used in

Example

subject:

v0, v4 of p rules; all subject fields of g rules

subject:usr_abc123

company:

v1, v3 of p rules; v2 of g rules

company:cmp_abc123

resource:

v2 of p rules

resource:chat

action:

v5 of p rules

action:read

When using the API you do not write these prefixes. The API accepts plain values (subject: "usr_abc123", resource: "chat", action: "read") and Gatekeeper adds/strips the prefixes when reading from or writing to the database. The prefixes only matter when you inspect raw policy rows (e.g. via adminPaginatedPolicies or getAllPolicies).

Special values

Several sentinel values are resolved dynamically at enforcement time instead of being compared literally:

Value

Valid in

Meaning

own (stored as company:own)

objectCompany (v3)

The object must belong to the same company as the requesting user. This is the standard value for tenant-scoped policies.

own (stored as subject:own)

objectOwner (v4)

The object must be owned by the requesting user themselves. Use this to grant users access to their own data only (e.g. their own chats).

ownGroup (stored as subject:ownGroup)

objectOwner (v4)

The object must be owned by a user who shares at least one group with the requesting user. Evaluated via system-managed g2 rules.

*

any field

Wildcard matches anything. subject:* in objectOwner means "regardless of who owns the object"; company:* in subjectCompany means "in any tenant" (used for platform-wide role defaults).

Instance-scoped resources. The resource field may target a single object instance using the format {resource}:{id}, e.g. assistant:asst_xyz789. The platform uses this itself: when access to a specific assistant is granted, Gatekeeper writes p rules with resource:assistant:{assistantId}. Because resource matching uses Casbin's keyMatch, a policy on the bare resource (resource:assistant) also covers all instance-scoped requests for that resource type.

Actions

The possible values for the action field (v5):

Action

Meaning

read

View a single object and its details

list

Enumerate objects of this type (e.g. list users, list memberships)

create

Create a new object

write

Create or modify objects

delete

Delete objects

manage

Administrative control configure, share, grant access, change settings

chat

Interact with an assistant in a conversation (specific to assistant)

Not every action is meaningful for every resource: chat only applies to assistants, and some resources only ever get checked with a subset of actions. When in doubt, check which actions the built-in roles grant on a resource (see next/services/gatekeeper/src/roles/roles-definition/).

Resources

The resource field (v2) accepts the following values (defined in GatekeeperResources, next/packages/backend/gatekeeper-utils/src/types/resources.ts). The descriptions indicate what each resource governs on the platform.

Identity and tenancy

Resource

Description

user

Platform user accounts

company

The tenant (company) entity itself and its settings

membership

A user's membership in a company

group

User groups (typically synced from the identity provider)

scim-key

API keys used for SCIM user provisioning

Chat

Resource

Description

chat

Chat conversations

message

Individual messages within chats

message-assessment

Automated assessments attached to messages (e.g. hallucination checks)

message-execution

Execution state of an assistant run for a message

message-log

Diagnostic logs attached to messages

user-prompt

User-saved prompts (personal prompt library)

translation

Translation functionality within chat

briefing

Briefings (scheduled/automated digest reports)

Knowledge base

Resource

Description

content

Documents and files in the knowledge base

folder

Folders organizing knowledge base content

chunk

Chunked and embedded segments of ingested documents

scope

Knowledge base scopes containers that group content for access control

scope-access

Access grants on scopes (who may use a scope)

scope:folder

The mapping between scopes and folders

resource-access

Generic access grants on shared resources (e.g. shared chats or content)

ingestion

The content ingestion pipeline (upload and processing of documents)

ingestion-metrics

Metrics about ingestion runs

company-meta

Company-level metadata used by ingestion

Assistants and spaces

Resource

Description

assistant

AI assistants (spaces). Supports instance scoping: assistant:{assistantId}

assistant-type

The catalog of assistant types

assistant-module-type

The catalog of module types available to assistants

assistant-template

Reusable assistant templates

module

Modules configured within an assistant

module-template

Reusable module templates

prompt

System prompts configured on assistants

tool

Tools available to assistants

language-model

Language model (LLM) configurations

openai

Direct access to the platform's OpenAI-compatible completion endpoints

Apps and integrations

Resource

Description

app

Registered applications (programmatic platform access)

api-key

API keys belonging to apps

endpoint

Webhook endpoints registered by apps

subscription

Event subscriptions (which events an app receives)

installation

App installations

request-log

Request logs of app/webhook traffic

mcp

MCP (Model Context Protocol) server integrations

mcp-tool-configuration

Configuration of tools exposed via MCP connectors

mcp-hub-virtual-server

Virtual MCP servers in the MCP Hub

mcp-hub-virtual-server-access

Access grants on MCP Hub virtual servers

mcp-hub-oauth-provider

OAuth provider configurations for the MCP Hub

service-now

The ServiceNow integration

Analytics and quality

Resource

Description

analytics

Analytics data (general)

analytics:chat-interactions

Aggregated chat interaction analytics

analytics:chat-interactions-detailed

Detailed per-interaction analytics

analytics:reference-stat

Statistics on knowledge base references in answers

analytics:user-chat-export

Export of user chat data

analytics:active-users

Active-user analytics

analytics:scheduler

Scheduled analytics report configuration

insights

Insights dashboards

statistics

Usage statistics

metrics

Client-side metrics reporting

model-usage

LLM usage (token consumption) data

benchmark

Benchmarking runs for evaluating assistant quality

feedback

User feedback on assistant answers

net-promoter-score

NPS survey responses

log

Application logs

Workflow features

Resource

Description

due-diligence

Due diligence questionnaire workflows

magic-table

Agentic (magic) table workspaces

stock-market-index

Stock market index data (finance features)

Platform configuration

Resource

Description

theme

UI theme configuration

font

Custom fonts for theming

notification

User notifications

notification-banner

Admin-managed notification banners

terms-and-conditions

Terms and conditions shown to users

feature-flag

Feature flag configuration

System roles

The platform ships 23 built-in roles. Policies whose subject is a role ID apply to every user holding that role (via g rules). Roles can inherit other roles for example, Company_Admin inherits User_Management_Admin, KB_Admin, Space_Admin, Chat_Admin, Benchmarking_Admin, Feedback_Admin, Analytics_Admin, Apps_Admin, and Module_Template_Admin.

Role ID

Description

Company_Admin

System administrator across a specific company (inherits most other admin roles)

User_Management_Admin

Can create, change and delete users

Chat_User

Uses the chat can only access their own data

Chat_User_Debug

Chat user with debug read access to chunks

Chat_Admin

Administers chat functionality company-wide

KB_Admin

Full administration of the knowledge base

KB_Manager

Can read and write knowledge base folders and content

KB_Viewer

Can read and access knowledge base content

KB_Viewer_Debug

Knowledge base viewer with debug access

KB_Metadata_Editor

Can edit metadata of knowledge base content

Space_Admin

Can create and configure spaces, grant access and delegate

Space_Owner

Can create spaces

Space_Manager

Can manage assistants via MANAGE access

Module_Template_Admin

Can create, update and delete module templates

Benchmarking_Admin

Administers benchmarking

Benchmarking_Viewer

Can download benchmarking sheets and results

Feedback_Admin

Can read, add and delete feedback

Feedback_Viewer

Can read feedback

Analytics_Admin

Can request, configure and download analytics

Apps_Admin

Can create and delete apps

App_Viewer

Can read app information

Connector_Admin

Can manage connectors

Connector_Viewer

Can view connectors

Custom roles created via the API get an ID prefixed with custom__ and behave like system roles: users are assigned via g rules, and the role's permissions are ordinary company-scoped p rules with the custom role ID as subject.

Worked examples

The examples below show policies as stored rows. Remember that when creating them via the API you omit the prefixes.

Role default: chat users may read their own chats

text
ptype: p
v0:    subject:Chat_User      (subject: the Chat_User role)
v1:    company:*              (applies in every tenant  platform default)
v2:    resource:chat          (resource: chats)
v3:    company:own            (object must belong to the user's own company)
v4:    subject:own            (object must be owned by the requesting user)
v5:    action:read            (action: read)
v6:    allow

Any user holding Chat_User (directly or via inheritance) may read chats but only chats they own, within their own company.

Custom grant: one user may manage a specific assistant

text
ptype: p
v0:    subject:usr_abc123                    (a specific user)
v1:    company:cmp_xyz789                    (their company)
v2:    resource:assistant:asst_def456        (one specific assistant)
v3:    company:cmp_xyz789                    (object company)
v4:    subject:*                             (regardless of who owns the assistant)
v5:    action:manage
v6:    allow

This is the instance-scoped pattern: the resource targets a single assistant by ID rather than all assistants.

Deny exception: block a group from deleting content

text
ptype: p
v0:    subject:group_interns    (a group)
v1:    company:cmp_xyz789
v2:    resource:content
v3:    company:own
v4:    subject:*
v5:    action:delete
v6:    deny

Even if members of group_interns hold a role that allows deleting content, this rule blocks it deny always wins over allow.

Role assignment (g rule)

text
ptype: g
v0:    subject:usr_abc123     (the user)
v1:    subject:Chat_User      (the role)
v2:    company:cmp_xyz789     (within this company)

This makes example 1 apply to usr_abc123 in company cmp_xyz789.

Managing policies via the API

Policies are managed through the Gatekeeper GraphQL admin API. All admin operations require an authenticated user with the user-management admin permission, and they operate within the caller's own company.

The policy input maps one-to-one onto the p rule fields with plain values, no prefixes:

graphql
input PolicyParamsInput {
  subject: String!         # v0  user ID, role ID, or group_{id}
  subjectCompany: String!  # v1  company ID or "*"
  resource: String!        # v2  resource, optionally instance-scoped ("assistant:asst_xyz")
  objectCompany: String!   # v3  company ID, "own", or "*"
  objectOwner: String!     # v4  user ID, "own", "ownGroup", or "*"
  action: String!          # v5  see Actions
  effect: PolicyEffect     # v6  ALLOW (default) or DENY
}

Key operations:

Operation

Type

Purpose

adminAddPolicy(input) / adminAddPolicies(input)

Mutation

Create one / multiple p rules

adminRemovePolicy(input) / adminRemovePolicies(input)

Mutation

Delete one / multiple p rules (exact match on all fields)

adminUpdatePolicy(input)

Mutation

Replace an existing p rule with a new one

adminAddGroupingPolicies(input) / adminRemoveGroupingPolicies(input)

Mutation

Create / delete g rules (role and group assignments)

adminCreateCustomRole(input) / adminUpdateCustomRole(...) / adminDeleteCustomRole(roleId)

Mutation

Manage custom roles (a named bundle of p rules)

adminPaginatedPolicies(input)

Query

Browse and filter existing policy rows

adminPolicyStats

Query

Policy counts for the company

adminGetAllRoles

Query

List system and custom roles

adminGetUserPermissions(userId)

Query

Inspect a user's effective permissions

Grouping policy input for g rules:

graphql
input GroupingPolicyCreateParamsInput {
  subject: String!  # v0  the member (user ID or group_{id})
  group: String!    # v1  the role ID or parent group
  company: String!  # v2  company ID
}

Practical guidance

  • Prefer roles over per-user policies. Create a custom role with the required p rules and assign users to it via g rules, instead of duplicating p rules per user.

  • Scope tightly. Use objectCompany: "own" unless you have a specific reason not to, and prefer objectOwner: "own" or "ownGroup" over "*" when the resource has meaningful ownership.

  • Use deny sparingly. A deny rule overrides every allow that matches the same request. Broad deny rules (wildcards) can lock users out in surprising ways.

  • Removal requires an exact match. adminRemovePolicy deletes the rule whose fields all match the input exactly it does not delete "all rules matching a pattern".

  • Never touch g2. Same-group relationships are maintained automatically by the platform.

Last updated