Skip to content

πŸ›‘οΈ Permissions System (ACL)ΒΆ

🎯 Overview¢

The Permissions System (Access Control List - ACL) provides fine-grained control over who can access what resources and perform which operations. It integrates seamlessly with the Authentication System to enforce role-based access control throughout Continuum.

πŸ“‹ PurposeΒΆ

The ACL System enables: - Role-Based Access Control (RBAC): Assign permissions based on roles - Resource-Level Permissions: Control access to specific collections - Operation-Level Permissions: Define which actions are allowed - Conditional Permissions: Apply filters to limit data access - Field-Level Security: Control access to specific fields

πŸ—οΈ ArchitectureΒΆ

graph TB
    Request[API Request]
    Auth[Authentication]

    subgraph "ACL System"
        RoleCheck{User Role?}
        PermLookup[Permission Lookup]
        PolicyEval[Policy Evaluation]
        FilterApply[Filter Application]
    end

    subgraph "Permission Storage"
        Roles[(Roles)]
        Permissions[(Permissions)]
        Policies[(Policies)]
    end

    subgraph "Access Decision"
        Allow[Allow Access]
        Deny[Deny Access 403]
        FilteredAccess[Filtered Access]
    end

    Request --> Auth
    Auth --> RoleCheck

    RoleCheck --> PermLookup
    PermLookup --> Roles
    PermLookup --> Permissions

    Permissions --> PolicyEval
    PolicyEval --> Policies

    PolicyEval -->|No Restrictions| Allow
    PolicyEval -->|Has Filters| FilterApply
    PolicyEval -->|Denied| Deny

    FilterApply --> FilteredAccess

    classDef acl fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    classDef storage fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
    classDef decision fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
    classDef deny fill:#ffebee,stroke:#c62828,stroke-width:2px

    class RoleCheck,PermLookup,PolicyEval,FilterApply acl
    class Roles,Permissions,Policies storage
    class Allow,FilteredAccess decision
    class Deny deny

πŸ”‘ Core ConceptsΒΆ

πŸ‘₯ RolesΒΆ

Roles are groups that define sets of permissions:

Role Typical Permissions Use Case
Admin Full system access System administrators
Editor Content CRUD, no schema changes Content managers
Author Create/update own content Content creators
Viewer Read-only access Consumers, clients
API User Programmatic access Integration services

πŸ”’ PermissionsΒΆ

Permissions define what actions a role can perform on which resources:

Structure: - Role: Which role this applies to - Resource: Which collection (e.g., "articles", "users") - Action: Which operation (e.g., "list", "create", "update") - Conditions: Optional filters or field restrictions

πŸ“‹ ActionsΒΆ

Standard actions available for resources:

Action HTTP Method Description
list GET List/query records
get GET Get single record
create POST Create new record
update POST/PUT Update existing record
destroy POST/DELETE Delete record
add POST Add relationship (M2M)
set POST Set relationship (M2O)
remove POST Remove relationship

βš™οΈ Permission ConfigurationΒΆ

πŸ“‹ Basic Permission StructureΒΆ

{
  "role": "editor",
  "resource": "articles",
  "action": "create",
  "scope": "all",
  "filter": null,
  "fields": null
}

🎯 Permission Levels¢

1️⃣ Public AccessΒΆ

No authentication required:

{
  "role": "*",
  "resource": "articles",
  "action": "list",
  "scope": "public"
}

2️⃣ Authenticated AccessΒΆ

Any logged-in user or valid API key:

{
  "role": "loggedIn",
  "resource": "articles",
  "action": "create",
  "scope": "all"
}

3️⃣ Role-Specific AccessΒΆ

Only specific roles:

{
  "role": "admin",
  "resource": "collections",
  "action": "*",
  "scope": "all"
}

πŸ” Conditional PermissionsΒΆ

πŸ“ Filter-Based PermissionsΒΆ

Limit access to records matching specific conditions:

Own Records OnlyΒΆ

{
  "role": "author",
  "resource": "articles",
  "action": "update",
  "filter": {
    "authorId": "{{ ctx.state.currentUser.id }}"
  }
}

Effect: Authors can only update their own articles.

Status-Based AccessΒΆ

{
  "role": "editor",
  "resource": "articles",
  "action": "list",
  "filter": {
    "status": {"$in": ["published", "review"]}
  }
}

Effect: Editors see only published or in-review articles.

Date-Based AccessΒΆ

{
  "role": "viewer",
  "resource": "articles",
  "action": "list",
  "filter": {
    "publishedAt": {"$lte": "{{ now }}"},
    "status": "published"
  }
}

Effect: Viewers see only published articles from the past.

🏷️ Field-Level Permissions¢

Control which fields can be accessed:

Read RestrictionsΒΆ

{
  "role": "viewer",
  "resource": "users",
  "action": "list",
  "fields": ["id", "name", "email"]
}

Effect: Viewers can only see id, name, and email fields.

Write RestrictionsΒΆ

{
  "role": "editor",
  "resource": "articles",
  "action": "update",
  "fields": ["title", "content", "excerpt"]
}

Effect: Editors can only update specific fields.

Hidden FieldsΒΆ

{
  "role": "author",
  "resource": "articles",
  "action": "get",
  "except": ["internalNotes", "seoAnalysis"]
}

Effect: Authors don't see internal fields.

🎯 Permission Examples¢

πŸ“š Blog System PermissionsΒΆ

Admin RoleΒΆ

{
  "role": "admin",
  "permissions": [
    {
      "resource": "*",
      "action": "*",
      "scope": "all"
    }
  ]
}

Full access to everything.

Editor RoleΒΆ

{
  "role": "editor",
  "permissions": [
    {
      "resource": "articles",
      "action": ["list", "get", "create", "update", "destroy"],
      "scope": "all"
    },
    {
      "resource": "tags",
      "action": ["list", "get", "create"],
      "scope": "all"
    },
    {
      "resource": "users",
      "action": ["list", "get"],
      "fields": ["id", "name", "email"]
    }
  ]
}

Editors can manage content but not modify schema or other users.

Author RoleΒΆ

{
  "role": "author",
  "permissions": [
    {
      "resource": "articles",
      "action": "list",
      "filter": {
        "authorId": "{{ ctx.state.currentUser.id }}"
      }
    },
    {
      "resource": "articles",
      "action": ["create", "update"],
      "filter": {
        "authorId": "{{ ctx.state.currentUser.id }}"
      },
      "fields": ["title", "content", "excerpt", "status"]
    },
    {
      "resource": "articles",
      "action": "get",
      "filter": {
        "$or": [
          {"authorId": "{{ ctx.state.currentUser.id }}"},
          {"status": "published"}
        ]
      }
    },
    {
      "resource": "tags",
      "action": ["list", "get"],
      "scope": "all"
    }
  ]
}

Authors can only manage their own articles and view published ones.

Viewer RoleΒΆ

{
  "role": "viewer",
  "permissions": [
    {
      "resource": "articles",
      "action": ["list", "get"],
      "filter": {
        "status": "published",
        "publishedAt": {"$lte": "{{ now }}"}
      },
      "fields": ["id", "title", "content", "publishedAt", "author", "tags"]
    },
    {
      "resource": "tags",
      "action": ["list", "get"],
      "scope": "all"
    }
  ]
}

Viewers can only read published articles.

πŸ”§ Managing PermissionsΒΆ

πŸ“‹ Via API (Programmatic)ΒΆ

List Role PermissionsΒΆ

GET /api/roles:get?filterByTk=editor&appends=permissions
X-App: main
Authorization: Bearer {admin-api-key}

Add Permission to RoleΒΆ

POST /api/roles/{role-id}/permissions:add
X-App: main
Authorization: Bearer {admin-api-key}
Content-Type: application/json

{
  "values": [
    {
      "resource": "articles",
      "action": "create",
      "scope": "all"
    }
  ]
}

Remove PermissionΒΆ

POST /api/roles/{role-id}/permissions:remove
X-App: main
Authorization: Bearer {admin-api-key}

{
  "values": [permission-id]
}

πŸ–₯️ Via UI (Administrative)ΒΆ

  1. Navigate to Settings β†’ ACL
  2. Select a Role
  3. Configure permissions for each resource
  4. Set conditions and field restrictions
  5. Save changes

πŸ” Security Best PracticesΒΆ

🎯 Principle of Least Privilege¢

DO: - βœ… Grant minimum necessary permissions - βœ… Use role hierarchies (viewer β†’ author β†’ editor β†’ admin) - βœ… Separate read and write permissions - βœ… Use filters to limit data access - βœ… Restrict field access when appropriate

DON'T: - ❌ Give everyone admin access - ❌ Grant blanket permissions without filters - ❌ Allow unrestricted schema modifications - ❌ Expose sensitive fields unnecessarily

πŸ”’ Filter SecurityΒΆ

DO: - βœ… Use ctx.state.currentUser.id for user-specific filters - βœ… Combine multiple conditions for security - βœ… Test filters thoroughly - βœ… Audit filter effectiveness

DON'T: - ❌ Use client-provided values in filters - ❌ Create overly complex filter logic - ❌ Rely solely on filters for critical security - ❌ Forget to handle edge cases

🏷️ Field Security¢

DO: - βœ… Hide sensitive data (passwords, API keys) - βœ… Separate public and internal fields - βœ… Use except to exclude specific fields - βœ… Document which fields are restricted

DON'T: - ❌ Expose internal identifiers unnecessarily - ❌ Return sensitive data in list operations - ❌ Allow modification of system fields - ❌ Forget to audit field access logs

🎯 Common Permission Patterns¢

1️⃣ Multi-Tenant IsolationΒΆ

Ensure users can only access their organization's data:

{
  "role": "member",
  "resource": "projects",
  "action": "*",
  "filter": {
    "organizationId": "{{ ctx.state.currentUser.organizationId }}"
  }
}

2️⃣ Hierarchical AccessΒΆ

Team leaders see their team's data:

{
  "role": "team-lead",
  "resource": "tasks",
  "action": ["list", "get", "update"],
  "filter": {
    "$or": [
      {"assignedTo": "{{ ctx.state.currentUser.id }}"},
      {"teamId": "{{ ctx.state.currentUser.teamId }}"}
    ]
  }
}

3️⃣ Time-Based AccessΒΆ

Content visible only during specific periods:

{
  "role": "subscriber",
  "resource": "courses",
  "action": "get",
  "filter": {
    "subscriptionStart": {"$lte": "{{ now }}"},
    "subscriptionEnd": {"$gte": "{{ now }}"}
  }
}

4️⃣ Approval WorkflowsΒΆ

Different permissions based on status:

{
  "role": "approver",
  "resource": "content",
  "action": "update",
  "filter": {
    "status": "pending-approval"
  },
  "fields": ["status", "approvalNotes"]
}

πŸ”§ TroubleshootingΒΆ

❌ Error: "No permissions" (403)¢

Check: 1. User's role assignment 2. Role's permissions for that resource/action 3. Filter conditions (may exclude the record) 4. Field restrictions (may not include requested fields)

Debug:

# Check user's role
GET /api/users:get?filterByTk={user-id}&appends=roles
X-App: main

# Check role's permissions
GET /api/roles:get?filterByTk={role-name}&appends=permissions
X-App: main

# Test with admin key
# If works with admin, it's a permission issue

❌ Filter Not Working¢

Common Issues: 1. Incorrect context variable syntax 2. Type mismatch in filter 3. Missing field in collection 4. Filter too restrictive

Debug:

# Check actual filter being applied
# Enable debug logging for ACL system
# Test without filter to verify data exists

❌ Field Access Denied¢

Check: 1. Field list in permission configuration 2. Using fields vs except 3. Field actually exists in collection 4. Not using reserved field names

πŸ“Š Permission AuditΒΆ

πŸ“ˆ Track Permission UsageΒΆ

GET /api/audit-logs:list?filter={"type":"permission-check"}
X-App: main
Authorization: Bearer {admin-api-key}

πŸ” Test PermissionsΒΆ

# Test as specific role
POST /api/permissions:test
X-App: main
Content-Type: application/json

{
  "role": "editor",
  "resource": "articles",
  "action": "update",
  "recordId": 123
}

Response:

{
  "allowed": true,
  "filters": {
    "authorId": 5
  },
  "fields": ["title", "content", "excerpt"]
}

  • Authentication: API key and user authentication
  • Multi-App Manager: Application-specific permissions
  • Collection Manager: Resource definitions
  • Best Practices: Security optimization

Note: Proper permission configuration is essential for data security and user experience. Always test thoroughly and follow the principle of least privilege.