Role-Based Access Control (RBAC)

Enterprise-grade access control with roles, policies, and granular permissions

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

  1. Navigate to Settings → Security → Roles
  2. Click "Create Role"
  3. Define role properties:
    • Name
    • Icon (optional)
    • Description
    • Parent Role (optional)
  4. Create or link a policy
  5. 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:

  1. User has a role assigned
  2. Role is linked to a policy
  3. Policy has permissions defined
  4. Permission filters are evaluated
  5. Field-level access is checked
  6. 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:

  1. Map Permissions: Convert old resource:action format to collection-based permissions
  2. Create Policies: Define equivalent policies in the system
  3. Assign Roles: Link users to appropriate roles
  4. Test Access: Verify permissions work as expected
  5. Update Code: Replace old permission checks with new API

Copyright © 2026. All rights reserved.