Reference

Roles & Authorization

8 min read

> **What you'll learn:** How TallCMS uses Filament Shield for role-based access control, including built-in roles, permissions, and artisan commands.

Roles & Authorization


Overview

TallCMS uses Filament Shield built on Spatie Permission for authorization:

ComponentPurpose
RolesGroups of permissions assigned to users
PermissionsIndividual access rights (e.g., Update:CmsPage)
PoliciesLaravel policy classes that check permissions

Built-in Roles

RolePurposeTypical Use
super_adminFull system accessSite owner, lead developer
administratorContent and settings managementSite manager
editorContent editing and publishingContent team lead
authorContent creation, submit for reviewContent contributor
site_ownerEnd-to-end management of their own site(s) in a SaaS flowNew signups via the Registration plugin

The site_owner Role

Introduced in v4.0.14 for the SaaS / site-builder flow. A site_owner gets full CRUD on pages, posts, categories, menus, media, comments, contact submissions, and the Template Gallery — but scoped to their own site(s) via policy (ChecksSiteOwnership trait + resource query scoping). They never see another tenant's records.

Syncing the role onto an existing install:

php artisan tallcms:shield-sync-site-owner

Idempotent — safe to run repeatedly. Creates the role + any missing permissions, doesn't touch other roles or existing user-role assignments.

  • Fresh installs get the role automatically via ShieldSeeder during tallcms:setup.
  • Updates via php artisan tallcms:update auto-sync it in the cache-clearing step.
  • Git-based deploys (where the built-in updater doesn't run) must call this command manually in the post-deploy script, after migrate.

Permission Naming Convention

Permissions follow the pattern: {Action}:{Resource}

Actions

ActionDescription
ViewAnyList/index resources
ViewView single resource
CreateCreate new resource
UpdateEdit existing resource
DeleteSoft-delete resource
ForceDeletePermanently delete
RestoreRestore soft-deleted
ReplicateDuplicate resource
ReorderChange sort order

Content-Specific Actions

ActionDescription
ApproveApprove pending content
SubmitForReviewSubmit draft for approval
ViewRevisionsView revision history
RestoreRevisionRestore previous revision
GeneratePreviewLinkCreate preview URLs

Permission Categories

Content Management

CategoryResourceDescription
CmsPagePagesStatic pages
CmsPostPostsBlog posts
CmsCategoryCategoriesPost categories
TallcmsMediaMediaMedia library
MediaCollectionCollectionsMedia collections
TallcmsMenuMenusNavigation menus

System Administration

CategoryResourceDescription
UserUsersUser accounts
RoleRolesRole management
SiteSettingsSettingsSite configuration
TallcmsContactSubmissionContactForm submissions

Embed code (analytics, tracking, chat widgets) — access follows Site edit permission via SitePolicy. There is no dedicated Manage:CodeInjection permission anymore; if a user can edit a Site, they can set its embed code. See Embed Code.

Standalone Features

CategoryResourceDescription
ThemeManagerThemesTheme management
PluginManagerPluginsPlugin management
PluginLicensesLicensesLicense keys
SystemUpdatesUpdatesSystem updates

Artisan Commands

Shield Commands

Generate Permissions

Generate permissions for Filament resources:

# Generate for all resources
php artisan shield:generate --all

# Generate for specific resource
php artisan shield:generate --resource=CmsPageResource

# Generate for specific panel
php artisan shield:generate --all --panel=admin

Create Super Admin

Assign super admin role to a user:

php artisan shield:super-admin

# Or specify user
php artisan shield:super-admin --user=1

Create Seeder

Generate a seeder from current roles/permissions:

php artisan shield:seeder

Creates database/seeders/ShieldSeeder.php for version control.

Setup Shield

Initial Shield installation:

php artisan shield:setup

Permission Commands

Show Permissions

Display roles and permissions matrix:

php artisan permission:show

Create Role

php artisan permission:create-role editor

Create Permission

php artisan permission:create-permission "CustomAction:CustomResource"

Assign Role to User

php artisan permission:assign-role editor user@example.com

Clear Permission Cache

php artisan permission:cache-reset

TallCMS Commands

Full Setup

Run complete TallCMS setup including roles:

php artisan tallcms:setup

Install Only

Run migrations and create default roles:

php artisan tallcms:install

Managing Roles in Admin Panel

View Roles

Navigate to Admin > Shield > Roles to see all roles and their permissions.

Create Role

  1. Click New Role
  2. Enter role name (lowercase, underscores)
  3. Select permissions
  4. Click Create

Edit Role Permissions

  1. Navigate to Admin > Shield > Roles
  2. Click the role to edit
  3. Check/uncheck permissions
  4. Click Save

Assign Role to User

  1. Navigate to Admin > Users
  2. Edit the user
  3. Select role(s) in the Roles field
  4. Click Save

Managing Permissions in Code

Check Permission

// Via user
$user->can('Update:CmsPage');
$user->cannot('ForceDelete:CmsPage');

// Via Gate
Gate::allows('Update:CmsPage');

// Via policy (in controller)
$this->authorize('update', $page);

Grant Permission to Role

use Spatie\Permission\Models\Role;

$role = Role::findByName('editor');
$role->givePermissionTo('Approve:CmsPage');
$role->givePermissionTo(['Approve:CmsPost', 'ViewRevisions:CmsPost']);

Revoke Permission

$role->revokePermissionTo('ForceDelete:CmsPage');

Sync Permissions

Replace all permissions for a role:

$role->syncPermissions([
    'ViewAny:CmsPage',
    'View:CmsPage',
    'Create:CmsPage',
    'Update:CmsPage',
]);

Assign Role to User

$user->assignRole('editor');
$user->assignRole(['editor', 'author']);

Remove Role from User

$user->removeRole('author');

Check Role

$user->hasRole('editor');
$user->hasAnyRole(['editor', 'administrator']);
$user->hasAllRoles(['editor', 'author']);

Creating Custom Permissions

1. Create the Permission

php artisan permission:create-permission "Export:CmsPage"

Or in code:

use Spatie\Permission\Models\Permission;

Permission::create(['name' => 'Export:CmsPage']);

2. Add to Policy

// app/Policies/CmsPagePolicy.php

public function export(User $user, CmsPage $page): bool
{
    return $user->can('Export:CmsPage');
}

3. Use in Controller

$this->authorize('export', $page);

4. Use in Filament Resource

// In your Resource class

public static function canExport(): bool
{
    return auth()->user()?->can('Export:CmsPage') ?? false;
}

Seeding Roles and Permissions

Create Seeder

// database/seeders/RolesAndPermissionsSeeder.php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;

class RolesAndPermissionsSeeder extends Seeder
{
    public function run(): void
    {
        // Reset cached roles and permissions
        app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

        // Create permissions
        $permissions = [
            'ViewAny:CmsPage', 'View:CmsPage', 'Create:CmsPage',
            'Update:CmsPage', 'Delete:CmsPage',
            'Approve:CmsPage', 'SubmitForReview:CmsPage',
        ];

        foreach ($permissions as $permission) {
            Permission::firstOrCreate(['name' => $permission]);
        }

        // Create roles and assign permissions
        $author = Role::firstOrCreate(['name' => 'author']);
        $author->givePermissionTo([
            'ViewAny:CmsPage', 'View:CmsPage', 'Create:CmsPage',
            'Update:CmsPage', 'SubmitForReview:CmsPage',
        ]);

        $editor = Role::firstOrCreate(['name' => 'editor']);
        $editor->givePermissionTo([
            'ViewAny:CmsPage', 'View:CmsPage', 'Create:CmsPage',
            'Update:CmsPage', 'Delete:CmsPage', 'Approve:CmsPage',
        ]);
    }
}

Run Seeder

php artisan db:seed --class=RolesAndPermissionsSeeder

Caching

Permissions are cached automatically. Clear cache after changes:

php artisan permission:cache-reset

Or in code:

app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();

Common Pitfalls

Permission changes not taking effectRun php artisan permission:cache-reset to clear the permission cache.

"There is no permission named X"The permission doesn't exist. Create it with php artisan permission:create-permission "X" or run php artisan shield:generate --all.

User has role but can't access resourceThe role may not have the required permission. Check with php artisan permission:show or in Admin > Shield > Roles.

New Filament resource has no permissionsRun php artisan shield:generate --resource=YourResource to generate permissions.


Next Steps

Comments

No comments yet. Be the first to share your thoughts!

Choose Theme