Authorization and Permissions

PagibleAI CMS uses a role-based permission system to control who can view, edit, publish, and delete pages, elements, and files. Permissions are stored per user, resolved at runtime, and enforced across the admin panel, GraphQL API, and frontend.

For Users

Managing Users with Artisan

The cms:user command is the primary way to create users, assign roles, and manage permissions from the command line.

Creating a User

# Create a new CMS user (prompts for password)
php artisan cms:user editor@example.com

# Create with a password directly
php artisan cms:user editor@example.com --password=secret123

# Create and immediately grant full access
php artisan cms:user editor@example.com --enable

If the user does not exist, the command creates a new account. Without --password, it will prompt you for one interactively.

Assigning Roles

# Assign the editor role
php artisan cms:user editor@example.com --role=editor

# Assign the publisher role
php artisan cms:user editor@example.com --role=publisher

# Grant full admin access
php artisan cms:user editor@example.com --role=admin

Adding and Removing Permissions

# Add specific permissions
php artisan cms:user editor@example.com --add=page:publish --add=element:publish

# Add all page permissions
php artisan cms:user editor@example.com --add="page:*"

# Add all view permissions across resources
php artisan cms:user editor@example.com --add="*:view"

# Remove specific permissions
php artisan cms:user editor@example.com --remove=page:purge

# Remove all publish permissions
php artisan cms:user editor@example.com --remove="*:publish"

# Disable a user (removes all permissions)
php artisan cms:user editor@example.com --disable

Listing Permissions and Roles

# Show all permissions for a user
php artisan cms:user editor@example.com --list

# Show all available roles and their permissions
php artisan cms:user --roles

Command Reference

Option

Description

--add= / -a

Grant permissions by name or pattern (page:*, *:view, *). Repeatable.

--remove= / -r

Revoke permissions by name or pattern. Repeatable.

--role=

Assign a named role (editor, publisher, admin, etc.)

--enable / -e

Grant all permissions (shorthand for --add="*")

--disable / -d

Remove all permissions

--list / -l

Show current permissions for the user

--roles

List all available roles and their permissions

--password= / -p

Set or update the user's password

--quiet / -q

Suppress output

Built-in Roles

PagibleAI ships with four roles. Each role bundles a set of permissions that determine what the user can do in the admin panel.

Role

Can Do

Cannot Do

admin

Everything

publisher

Create, edit, publish, and delete pages, elements, and files

System configuration beyond page config

editor

Create and edit pages, elements, and files

Publish content or permanently delete

viewer

View pages, elements, and files

Edit, create, publish, or delete anything

Run php artisan cms:user --roles to see the exact permission sets for each role in your installation.

For Administrators

Permissions

Every authorization check uses an permission string in the format resource:operation. The built-in permissions are:

Pages:

  • page:view — View pages and their content
  • page:save — Save changes to existing pages
  • page:add — Create new pages
  • page:drop — Soft-delete pages
  • page:keep — Restore soft-deleted pages
  • page:purge — Permanently delete pages
  • page:publish — Publish page versions
  • page:move — Move pages in the page tree
  • page:config — Edit page configuration

Elements:

  • element:view — View shared content elements
  • element:save — Save changes to elements
  • element:add — Create new elements
  • element:drop — Soft-delete elements
  • element:keep — Restore soft-deleted elements
  • element:purge — Permanently delete elements
  • element:publish — Publish element versions

Files:

  • file:view — View uploaded files
  • file:save — Save changes to files
  • file:add — Upload new files
  • file:drop — Soft-delete files
  • file:keep — Restore soft-deleted files
  • file:purge — Permanently delete files
  • file:publish — Publish file versions

Defining Custom Roles

Add your own roles in config/cms.php under the roles key. Roles support a flexible syntax:

Syntax

Example

Meaning

Single permission

"page:view"

Grants one specific action

Wildcard

"page:*"

Grants all actions for a resource

Super wildcard

"*"

Grants every registered action

Denial

"!page:purge"

Explicitly denies one action

Wildcard denial

"!*:publish"

Denies an operation across all resources

Role reference

"editor"

Includes all permissions from another role

Denials always take priority. When permissions are resolved:

  1. Role names are expanded recursively
  2. Wildcards are expanded to matching actions
  3. Denials are subtracted last
// config/cms.php
'roles' => [
    'admin'          => ['*'],
    'reviewer'       => ['page:view', 'element:view', 'file:view', 'page:keep'],
    'media-manager'  => ['file:*', 'image:*', '!file:purge'],
    'senior-editor'  => ['editor', 'page:publish', 'element:publish'],
],

In this example, reviewer can view content and restore versions, media-manager has full file access except permanent deletion, and senior-editor inherits all editor permissions plus publish rights.

Multi-Tenancy

All models are scoped to a tenant_id resolved via Tenancy::$callback. Permission checks operate within this boundary — users can only access content belonging to their tenant. You can assign different cmsperms values per user per tenant at the application level.

For Developers

Direct User Assignment

Permissions are stored in the cmsperms JSON column on the users table as an array of role names and individual permission strings. PagibleAI automatically casts it to a PHP array.

// Full admin
$user->cmsperms = ['admin'];

// Publisher who cannot permanently delete
$user->cmsperms = ['publisher', '!*:purge'];

// Viewer with an extra AI permission
$user->cmsperms = ['viewer', 'image:imagine'];

// Multiple roles combined (union of both)
$user->cmsperms = ['editor', 'publisher'];

Checking Permissions in Code

Use the static Permission class to check, grant, or revoke permissions at runtime:

use Aimeos\Cms\Permission;

// Check a single action
if (Permission::can('page:publish', $user)) {
    // user can publish pages
}

// Get all actions with granted/denied status
$perms = Permission::get($user);
// ['page:view' => true, 'page:publish' => false, ...]

// Grant permissions at runtime
Permission::add('page:publish', $user);
Permission::add(['file:add', 'file:save'], $user);

// Revoke permissions at runtime
Permission::remove('page:purge', $user);

// List all registered actions
$actions = Permission::all();

// List all role names
$roles = Permission::roles();

// Expand a role to its permissions
$perms = Permission::role('editor');

Registering Custom Permissions

Register additional permission names for your own packages in a service provider:

use Aimeos\Cms\Permission;

Permission::register(['seo:analyze', 'seo:submit']);

Registered actions appear in Permission::all() and can be assigned to users or included in role definitions.

Custom Authorization

Replace the default permission logic with closures to integrate an external authorization system like Spatie Permission, Bouncer, or an identity provider:

use Aimeos\Cms\Permission;

// Override permission checks
Permission::canUsing(function(string $action, $user) {
    return ExternalRbac::check($user->id, $action);
});

// Override granting
Permission::addUsing(function(array $actions, $user) {
    ExternalRbac::grant($user->id, $actions);
    return $user;
});

// Override revoking
Permission::removeUsing(function(array $actions, $user) {
    ExternalRbac::revoke($user->id, $actions);
    return $user;
});

Callbacks take priority over the default cmsperms-based resolution. Pass null to restore the default behavior.

GraphQL Permission Directive

The GraphQL API enforces permissions using the @cmsPermission directive on mutation and query fields. Any request from a user who lacks the required action receives a GraphQL error.

The admin panel automatically hides UI elements for actions the current user cannot perform, based on the same permission checks.

Frontend Permission Helpers

PagibleAI's Blade helpers are permission-aware:

  • cms($item, $prop) — Returns the latest draft version if the user has page:view, otherwise the published version
  • cmsroute($page) — Uses the draft URL path for users with page:view, the published path for everyone else
  • cmsref($page, $item) — Resolves shared element references respecting element:view

This lets editors preview unpublished changes on the live site while visitors always see published content.