Role-Based Access Control (RBAC)
Role-Based Access Control (RBAC)
Cliqer implements enterprise-grade Role-Based Access Control (RBAC) with granular control over user access to features and data.
System Architecture
RBAC in Cliqer consists of:
- Roles: Named role definitions with hierarchy support
- Policies: Permission policies with admin and app access flags
- Permissions: Collection-level permissions (create, read, update, delete)
- Access Control: Links between roles/users and policies
Default Roles
Cliqer includes several predefined roles:
Administrator
- Full System Access: Complete control over all features
- User Management: Create, edit, and delete users
- Settings Management: Configure system settings
- Billing Access: Manage subscriptions and payments
- Security Configuration: Manage security settings
Manager
- Team Management: Manage team members
- Resource Access: Full access to team resources
- Analytics: View team analytics and reports
- Limited Settings: Configure team-specific settings
Member
- Standard Access: Access to assigned resources
- Collaboration: Create and edit team content
- View Analytics: View personal analytics
Guest
- Read-Only Access: View shared resources
- Limited Interaction: Cannot modify data
- Restricted Features: Limited to essential features
Permission Structure
Actions
Each resource supports these permission actions:
- Create: Add new items to the system
- Read: View existing items
- Update: Modify existing items
- Delete: Remove items from the system
Collections
Each permission defines:
{
collection: 'users', // Collection name
action: 'read', // create | read | update | delete
permissions: {}, // Filter rules (optional)
validation: {}, // Validation rules (optional)
presets: {}, // Default values (optional)
fields: ['*'] // Accessible fields
}
Policy Configuration
Policies contain:
{
name: 'Content Editor Policy',
icon: 'edit',
description: 'Allows editing content',
admin_access: false, // Full admin panel access
app_access: true, // Application access
enforce_tfa: false, // Require 2FA
ip_access: [], // IP whitelist (optional)
permissions: [ // Array of permission objects
{
collection: 'posts',
action: 'create',
fields: ['*']
}
]
}
Permission Inheritance
Roles support hierarchical inheritance:
Administrator (Parent)
├── Manager
│ ├── Team Lead
│ └── Department Head
└── Super Admin
Child roles inherit all permissions from parent roles and can have additional permissions granted.
Creating Custom Roles
Via Admin Panel
- Navigate to Settings → Security → Roles
- Click "Create Role"
- Define role properties:
- Name
- Icon (optional)
- Description
- Parent Role (optional)
- Create or link a policy
- Configure permissions per collection
Via API
// Create a new role
const role = await $fetch('/api/admin/rbac/roles', {
method: 'POST',
body: {
name: 'Content Editor',
icon: 'edit',
description: 'Manages content',
parent: parentRoleId // optional
}
})
// Create policy via admin panel or API
const policy = await $fetch('/api/admin/rbac/policies', {
method: 'POST',
body: {
name: 'Content Editor Policy',
admin_access: false,
app_access: true,
permissions: [
{
collection: 'posts',
action: 'create',
fields: ['*']
},
{
collection: 'posts',
action: 'update',
fields: ['*']
}
]
}
})
// Link policy to role
await $fetch('/api/admin/rbac/role-assignments', {
method: 'POST',
body: {
role: role.id,
policy: policy.id
}
})
Permission Checking
Client-Side
// Check single permission
const canManageUsers = await hasPermission('users', 'update')
// Check multiple permissions (AND - all must pass)
const canViewActivity = await hasAllPermissions([
{ collection: 'activity', action: 'read' },
{ collection: 'users', action: 'read' }
])
// Check multiple permissions (OR - at least one must pass)
const canManageSystem = await hasAnyPermission([
{ collection: 'users', action: 'create' },
{ collection: 'users', action: 'delete' }
])
// Get user's current role
const { role } = useAuth()
console.log('User role:', role)
Server-Side
Use middleware to protect API endpoints:
export default defineEventHandler(async (event) => {
// Require specific permission
requirePermission('users', 'create'),
// Your endpoint logic
})
Permission Filters
Restrict data access based on user context:
{
"collection": "users",
"action": "read",
"permissions": {
"tenant_id": {
"_eq": "$CURRENT_USER.tenant_id"
}
}
}
Use variables:
$CURRENT_USER- Current user object$CURRENT_ROLE- Current role object$NOW- Current timestamp$NOW(<adjustment>)- Relative time (e.g.,$NOW(-7 days))
Field-Level Permissions
Control which fields users can access:
{
"collection": "users",
"action": "read",
"fields": ["id", "email", "first_name", "last_name"],
"permissions": {}
}
Exclude sensitive fields:
{
"collection": "users",
"action": "update",
"fields": ["first_name", "last_name", "avatar"],
"permissions": {
"id": {
"_eq": "$CURRENT_USER"
}
}
}
Advanced Scenarios
Multi-Tenant Access Control
Ensure users only see their tenant's data:
{
"collection": "posts",
"action": "read",
"permissions": {
"tenant_id": {
"_eq": "$CURRENT_USER.tenant_id"
}
}
}
Time-Based Permissions
Grant access during specific hours:
{
"collection": "reports",
"action": "read",
"permissions": {
"_and": [
{
"created_at": {
"_gte": "$NOW(-30 days)"
}
},
{
"tenant_id": {
"_eq": "$CURRENT_USER.tenant_id"
}
}
]
}
}
Conditional Permissions
Allow different access based on item status:
{
"collection": "posts",
"action": "update",
"permissions": {
"_or": [
{
"author": {
"_eq": "$CURRENT_USER"
},
"status": {
"_eq": "draft"
}
},
{
"status": {
"_eq": "published"
}
}
]
}
}
Audit & Activity Logging
All permission changes are logged:
{
action: 'permissions.update',
user: userId,
timestamp: new Date(),
changes: {
collection: 'users',
action: 'create',
added: true
}
}
Permission Resolution Flow
When a user attempts an action:
- User has a role assigned
- Role is linked to a policy
- Policy has permissions defined
- Permission filters are evaluated
- Field-level access is checked
- Action is allowed or denied
Composables
useRBAC()
const {
hasPermission,
hasAllPermissions,
hasAnyPermission,
currentRole,
currentPolicy
} = useRBAC()
// Usage
const canEdit = await hasPermission('users', 'read')
if (!canEdit) {
console.error('Permission denied')
}
requirePermission()
Server-side middleware helper:
export default defineEventHandler(async (event) => {
await requirePermission(event, 'users', 'create')
// If we reach here, user has permission
})
Common Permission Patterns
Read-Only Access
{
"permissions": [
{ "collection": "posts", "action": "read" }
]
}
Own Data Only
{
"permissions": {
"user_id": {
"_eq": "$CURRENT_USER"
}
}
}
Tenant Isolation
{
"permissions": {
"tenant_id": {
"_eq": "$CURRENT_USER.tenant_id"
}
}
}
Migration Guide
If migrating from a custom RBAC system:
- Map Permissions: Convert old
resource:actionformat to collection-based permissions - Create Policies: Define equivalent policies in the system
- Assign Roles: Link users to appropriate roles
- Test Access: Verify permissions work as expected
- Update Code: Replace old permission checks with new API