Permission metadata defines access control rules for objects, fields, actions, and views using Role-Based Access Control (RBAC) and field-level security.
ObjectQL's permission system provides a pure RBAC model with:
Role-based access control : Define roles and assign permissions to roles
Object-level permissions : Control CRUD operations on entire objects
Field-level security : Hide/protect sensitive fields from unauthorized users
Record-level rules : Dynamic filtering based on ownership, sharing, or custom rules
Action permissions : Control who can execute specific actions
View permissions : Restrict access to specific UI views
File Naming Convention: <object_name>.permission.yml
The filename (without the .permission.yml extension) automatically identifies which object these permission rules apply to.
Examples:
project.permission.yml → Applies to object: project
customer_order.permission.yml → Applies to object: customer_order
# File: project.permission.yml
# Object is inferred from filename!
description : Permission rules for project object
# Role Definitions
roles :
- admin
- manager
- developer
- viewer
# Object-Level Permissions
object_permissions :
create : [ admin , manager ]
read : [ admin , manager , developer , viewer ]
update : [ admin , manager ]
delete : [ admin ]
# Field-Level Security
field_permissions :
budget :
read : [ admin , manager ]
update : [ admin ]
internal_notes :
read : [ admin , manager ]
update : [ admin , manager ]
# Record-Level Rules
record_rules :
- name : owner_full_access
description : Project owner has full access
condition :
field : owner_id
operator : "="
value : $current_user.id
permissions :
read : true
update : true
delete : true
- name : team_member_access
description : Team members can view and edit
condition :
field : team_members
operator : contains
value : $current_user.id
permissions :
read : true
update : true
delete : false
# Action Permissions
action_permissions :
approve_project :
execute : [ admin , manager ]
archive_project :
execute : [ admin ]
Control basic CRUD operations on objects.
Permission Description createCreate new records readView existing records updateModify existing records deleteDelete records view_allSee all records (bypass ownership rules) modify_allEdit all records (bypass ownership rules)
object_permissions :
# Standard users
create : [ user ]
read : [ user ]
update : [ user ] # Limited by record rules
delete : [] # Nobody can delete
# Admins have full access
view_all : [ admin ]
modify_all : [ admin ]
Restrict access to specific fields based on roles.
field_permissions :
# Sensitive field - admins only
social_security_number :
read : [ admin , hr_manager ]
update : [ admin ]
# Financial data - finance team only
salary :
read : [ admin , finance_manager ]
update : [ admin , finance_manager ]
# System fields - read-only for most users
created_by :
read : [ admin , manager , user ]
update : [] # System managed
# Public field - everyone can read
name :
read : [ admin , manager , user , guest ]
update : [ admin , manager , user ]
Fields inherit object-level permissions unless explicitly overridden.
# If object read permission is [user], all fields are readable by [user]
# unless field_permissions specifies otherwise
object_permissions :
read : [ user ]
field_permissions :
# This field is MORE restrictive than object level
salary :
read : [ admin ]
Dynamic access control based on record data and user context.
record_rules :
# Rule 1: Owner Access
- name : owner_access
priority : 100
description : Record owner has full access
condition :
type : simple
field : owner_id
operator : "="
value : $current_user.id
permissions :
read : true
update : true
delete : true
# Rule 2: Department Access
- name : department_access
priority : 50
description : Same department can view
condition :
type : simple
field : department_id
operator : "="
value : $current_user.department_id
permissions :
read : true
update : false
delete : false
# Rule 3: Complex Condition
- name : approved_public_access
priority : 10
description : Approved records are public
condition :
type : complex
expression :
- field : status
operator : "="
value : approved
- and
- field : is_public
operator : "="
value : true
permissions :
read : true
update : false
delete : false
When multiple rules match, the highest priority rule takes precedence. Default priority is 0.
Type Description simpleSingle field comparison complexMultiple conditions with AND/OR logic formulaCustom JavaScript/formula expression lookupCheck related record data
Available in permission conditions:
Variable Description $current_user.idCurrent user's ID $current_user.roleCurrent user's role $current_user.department_idUser's department $current_user.team_idUser's team $current_dateCurrent date $current_timestampCurrent timestamp
Extend access beyond owner and role-based rules.
sharing_rules :
# Manual Sharing
- name : manual_share
type : manual
description : Users can manually share records
enabled : true
permissions :
read : true
update : false
delete : false
# Criteria-based Sharing
- name : public_projects
type : criteria
description : Public projects visible to all
condition :
field : visibility
operator : "="
value : public
shared_with :
type : role
roles : [ user , guest ]
permissions :
read : true
update : false
# Team-based Sharing
- name : team_sharing
type : team
description : Share with team members
team_field : assigned_team_id
permissions :
read : true
update : true
Control execution of custom actions.
action_permissions :
# Record Action
approve_order :
execute : [ manager , admin ]
conditions :
# Can only approve if order is pending
- field : status
operator : "="
value : pending
# Can only approve orders in their department
- field : department_id
operator : "="
value : $current_user.department_id
# Global Action
import_data :
execute : [ admin ]
rate_limit :
requests_per_hour : 10
Control access to specific views.
view_permissions :
# List View
all_projects :
access : [ admin , manager , developer ]
# Kanban View
project_kanban :
access : [ admin , manager ]
# Report View
financial_dashboard :
access : [ admin , finance_manager ]
field_restrictions :
profit_margin :
visible_to : [ admin ]
Automatically filter queries based on permissions.
row_level_security :
enabled : true
default_rule :
# Users only see their own records by default
field : owner_id
operator : "="
value : $current_user.id
exceptions :
# Admins bypass RLS
- role : admin
bypass : true
# Managers see their department
- role : manager
condition :
field : department_id
operator : "="
value : $current_user.department_id
Mask sensitive data for unauthorized users.
field_masking :
# Credit Card Numbers
credit_card :
mask_format : "****-****-****-{last4}"
visible_to : [ admin , finance ]
# Email Addresses
email :
mask_format : "{first}***@{domain}"
visible_to : [ admin , user_owner ]
# Phone Numbers
phone :
mask_format : "***-***-{last4}"
visible_to : [ admin , hr ]
Track permission changes and access.
audit :
enabled : true
# Log these events
events :
- permission_grant
- permission_revoke
- access_denied
- sensitive_field_access
# Retention period
retention_days : 365
# Alert on suspicious activity
alerts :
- event : access_denied
threshold : 5
window_minutes : 10
notify : [ security_team ]
// Check if user can perform operation
const canUpdate = await objectql. checkPermission ({
user: currentUser,
object: 'projects' ,
operation: 'update' ,
recordId: 'proj_123'
});
// Check field access
const canViewSalary = await objectql. checkFieldPermission ({
user: currentUser,
object: 'employees' ,
field: 'salary' ,
operation: 'read' ,
recordId: 'emp_456'
});
Hooks and actions receive permission context:
// In a hook
beforeUpdate : async ({ user , permissions }) => {
if ( ! permissions. canUpdate ( 'budget' )) {
throw new Error ( 'No permission to update budget' );
}
}
Principle of Least Privilege : Grant minimum necessary permissions
Define Clear Roles : Create well-defined roles that match organizational structure
Test Permissions : Validate permission rules with different user roles
Document Rules : Add clear descriptions to all permission rules
Regular Audits : Review permissions regularly for compliance
Separation of Duties : Prevent conflicts of interest with permission design
Default Deny : Deny access unless explicitly granted
SQL Injection : All permission filters use parameterized queries
Privilege Escalation : Validate permission changes require admin access
Session Management : Permissions cached per session, invalidated on role change
API Security : Rate limiting on permission checks to prevent DoS
Audit Logging : All permission denials logged for security analysis