Craft CMS User Groups and Permissions | OpsBlu Docs

Craft CMS User Groups and Permissions

Configure user groups, assign permissions, and implement role-based access control in Craft CMS for effective user management.

Complete guide to configuring user groups, assigning permissions, and implementing role-based access control (RBAC) in Craft CMS.

Understanding User Groups

User groups in Craft CMS organize users and define their permissions:

  • Permission Assignment - Assign permissions to groups, not individual users
  • Multiple Groups - Users can belong to multiple groups
  • Permission Inheritance - Users inherit all permissions from all their groups
  • Custom Fields - Each group can have unique custom fields

Creating User Groups

Via Control Panel

  1. Navigate to Settings → Users → User Groups
  2. Click + New user group
  3. Configure the group:
    • Name - Display name for the group
    • Handle - System handle (used in code)
    • Description - Optional description
    • Permissions - Select group permissions

Common User Group Setup

Structure:
├── Administrators (Full access)
├── Editors (Content + limited settings)
├── Authors (Own content only)
├── Members (Front-end only, no CP access)
└── Guests (Not logged in)

Permission Types

System Permissions

Control Panel Access

Access the Control Panel
├── Required for any CP access
└── Without this, users are front-end only

Access the Control Panel when the system is offline
├── Allow access during maintenance
└── Typically for administrators only

Perform Craft CMS and plugin updates
├── Install/update Craft and plugins
└── Critical system permission

User Permissions

Edit users
├── Can create/edit user accounts
└── Can assign to groups they belong to

Administrate users
├── Full user management
├── Can assign users to any group
└── Can change admin status

Register users
├── Can create new user accounts
└── Useful for customer service roles

Assign user permissions
├── Can modify individual user permissions
└── Should be limited to administrators

Assign users to user groups
├── Can add/remove users from groups
└── Limited to groups they belong to

Delete users
└── Permanent user removal

Content Permissions

Entry Permissions (Per Section)

View entries
├── Can see entries in this section
└── Base permission for all entry work

Create entries
├── Can create new entries
└── May be limited to drafts

Save entries
├── Can save changes to entries
└── Includes own and others' entries

Delete entries
├── Can permanently delete entries
└── Separate from "Delete own entries"

Publish entries
├── Can change entry status to Live
└── May require approval workflow

Edit other authors' entries
├── Can edit entries created by others
└── Important for editorial workflow

Publish other authors' entries
├── Can publish entries created by others
└── Typically for editors/reviewers

Delete other authors' entries
└── Can delete entries created by others

Asset Permissions (Per Volume)

View assets
├── Can see assets in this volume
└── Required for all asset operations

Save assets
├── Can upload new assets
└── Can edit existing assets

Delete assets
└── Can permanently delete assets

Replace files
├── Can replace asset files
└── Maintains asset ID and references

Edit images
├── Can use image editor
└── Crop, rotate, adjust images

Create subfolders
└── Can organize assets into folders

Category Permissions

View categories
Save categories
Delete categories

Configuring Group Permissions

Example: Editors Group

Configure a typical editors group with appropriate permissions:

Editors Group Configuration:

Control Panel:
☑ Access the Control Panel
☐ Access CP when offline
☐ Perform updates

Users:
☑ Edit users (own group only)
☐ Administrate users
☐ Delete users

Entries - Blog Section:
☑ View entries
☑ Create entries
☑ Save entries
☑ Delete entries (own only)
☑ Publish entries (own only)
☑ Edit other authors' entries
☑ Publish other authors' entries
☐ Delete other authors' entries

Assets - Documents Volume:
☑ View assets
☑ Save assets
☐ Delete assets
☑ Replace files
☑ Edit images
☑ Create subfolders

Settings:
☐ Edit site settings
☐ Edit plugin settings

Example: Authors Group

Configure a writers/authors group:

Authors Group Configuration:

Control Panel:
☑ Access the Control Panel
☐ Access CP when offline
☐ Perform updates

Users:
☐ Edit users
☐ Administrate users

Entries - Blog Section:
☑ View entries
☑ Create entries
☑ Save entries
☑ Delete entries (own only)
☐ Publish entries (requires approval)
☐ Edit other authors' entries
☐ Publish other authors' entries

Assets - Images Volume:
☑ View assets
☑ Save assets
☐ Delete assets
☑ Replace files (own only)
☑ Edit images
☐ Create subfolders

Example: Members Group (Front-End Only)

Configure a members group for front-end users:

Members Group Configuration:

Control Panel:
☐ Access the Control Panel

Users:
☐ All user permissions disabled

Entries:
☐ All entry permissions disabled
(Front-end users don't access CP)

Custom Permissions:
(Via custom plugin or module)
☑ Access member area
☑ Edit own profile
☑ Submit comments
☑ View premium content

Section-Specific Permissions

Per-Section Configuration

Different sections can have different permission requirements:

{# Check section-specific permissions #}

{% if currentUser and currentUser.can('editEntries:blog') %}
  <a href="{{ cpUrl('entries/blog/new') }}">Create Blog Post</a>
{% endif %}

{% if currentUser and currentUser.can('editEntries:news') %}
  <a href="{{ cpUrl('entries/news/new') }}">Create News Article</a>
{% endif %}

{% if currentUser and currentUser.can('publishEntries:blog') %}
  <button>Publish</button>
{% else %}
  <button>Save Draft</button>
{% endif %}

Volume-Specific Permissions

Control asset access per volume:

{# Check volume-specific permissions #}

{% if currentUser and currentUser.can('saveAssetInVolume:documents') %}
  <input type="file" name="document">
{% endif %}

{% if currentUser and currentUser.can('deleteAssetInVolume:images') %}
  <button>Delete Image</button>
{% endif %}

Checking Permissions in Templates

Basic Permission Checks

{# Check if user has specific permission #}
{% if currentUser and currentUser.can('accessCp') %}
  <a href="{{ cpUrl() }}">Control Panel</a>
{% endif %}

{# Check multiple permissions #}
{% if currentUser and
      currentUser.can('editEntries:blog') and
      currentUser.can('publishEntries:blog') %}
  <p>Full blog editing access</p>
{% endif %}

{# Check if user is in group #}
{% if currentUser and currentUser.isInGroup('editors') %}
  <div class="editor-tools">
    {# Editor-specific tools #}
  </div>
{% endif %}

{# Check multiple groups #}
{% if currentUser and
      (currentUser.isInGroup('editors') or
       currentUser.isInGroup('administrators')) %}
  <p>Administrative access</p>
{% endif %}

Advanced Permission Logic

{# Check if user can edit a specific entry #}
{% set entry = craft.entries().id(123).one() %}

{% if currentUser %}
  {% set canEdit = false %}

  {# Can edit own entries #}
  {% if entry.authorId == currentUser.id and
        currentUser.can('editEntries:' ~ entry.section.handle) %}
    {% set canEdit = true %}
  {% endif %}

  {# Can edit others' entries #}
  {% if currentUser.can('editPeerEntries:' ~ entry.section.handle) %}
    {% set canEdit = true %}
  {% endif %}

  {# Administrators can edit anything #}
  {% if currentUser.admin %}
    {% set canEdit = true %}
  {% endif %}

  {% if canEdit %}
    <a href="{{ entry.cpEditUrl }}">Edit Entry</a>
  {% endif %}
{% endif %}

Permission Hierarchies

Permission Dependencies

Some permissions require others:

To delete entries:
├── Must have "View entries"
└── Must have "Delete entries"

To publish entries:
├── Must have "View entries"
├── Must have "Save entries"
└── Must have "Publish entries"

To edit other authors' entries:
├── Must have "View entries"
├── Must have "Save entries"
└── Must have "Edit other authors' entries"

Admin Override

Administrators bypass all permission checks:

{# Admin users have all permissions #}
{% if currentUser and currentUser.admin %}
  <p>Administrator - Full Access</p>
{% else %}
  {# Check specific permissions #}
{% endif %}

Custom Permission Implementation

Via Custom Module

Create custom permissions for specific features:

<?php
// modules/userpermissions/Module.php

namespace modules\userpermissions;

use Craft;
use craft\events\RegisterUserPermissionsEvent;
use craft\services\UserPermissions;
use yii\base\Event;
use yii\base\Module as BaseModule;

class Module extends BaseModule
{
    public function init()
    {
        parent::init();

        Event::on(
            UserPermissions::class,
            UserPermissions::EVENT_REGISTER_PERMISSIONS,
            function(RegisterUserPermissionsEvent $event) {
                $event->permissions[] = [
                    'heading' => 'Custom Features',
                    'permissions' => [
                        'accessMemberArea' => [
                            'label' => 'Access member area',
                        ],
                        'viewPremiumContent' => [
                            'label' => 'View premium content',
                        ],
                        'submitComments' => [
                            'label' => 'Submit comments',
                        ],
                        'moderateComments' => [
                            'label' => 'Moderate comments',
                        ],
                    ],
                ];
            }
        );
    }
}

Use custom permissions in templates:

{% if currentUser and currentUser.can('accessMemberArea') %}
  {{ include('_members/dashboard') }}
{% endif %}

{% if currentUser and currentUser.can('viewPremiumContent') %}
  {{ entry.premiumContent }}
{% endif %}

Multi-Site Permissions

Per-Site User Access

Configure which sites users can access:

// Via Control Panel:
// User → Edit → Sites
// Select which sites this user can access

// Or programmatically:
$user = craft\elements\User::find()->id(123)->one();
$user->setSiteIds([1, 3, 5]); // Can access sites 1, 3, and 5
Craft::$app->elements->saveElement($user);

Check Site Access in Templates

{# Check if user can access current site #}
{% if currentUser and currentUser.canAccessSite(currentSite) %}
  <p>Access granted for {{ currentSite.name }}</p>
{% else %}
  <p>You don't have access to this site</p>
{% endif %}

{# List sites user can access #}
{% if currentUser %}
  <ul>
    {% for site in craft.app.sites.allSites %}
      {% if currentUser.canAccessSite(site) %}
        <li>{{ site.name }}</li>
      {% endif %}
    {% endfor %}
  </ul>
{% endif %}

Best Practices

1. Principle of Least Privilege

Grant only the minimum permissions required:

BAD: Give everyone "Administrators" group
GOOD: Create specific groups for each role

2. Use Groups, Not Individual Permissions

Assign permissions to groups, not individual users:

BAD: Manually set permissions for each user
GOOD: Create groups and assign users to groups

3. Document Permission Structure

Maintain documentation of your permission model:

# Permission Structure

## Administrators
- Full system access
- Can manage users and settings
- Can publish to production

## Editors
- Can create and edit all content
- Can publish content
- Cannot access system settings

## Authors
- Can create and edit own content
- Cannot publish (requires approval)
- Limited asset access

4. Regular Permission Audits

Review user permissions regularly:

{# Generate permission audit report #}
{% set users = craft.users().all() %}

<table>
  <thead>
    <tr>
      <th>User</th>
      <th>Groups</th>
      <th>Last Login</th>
      <th>Status</th>
    </tr>
  </thead>
  <tbody>
    {% for user in users %}
      <tr>
        <td>{{ user.fullName }}</td>
        <td>
          {% for group in user.groups %}
            {{ group.name }}{{ not loop.last ? ', ' }}
          {% endfor %}
        </td>
        <td>{{ user.lastLoginDate|date('Y-m-d H:i') }}</td>
        <td>{{ user.status }}</td>
      </tr>
    {% endfor %}
  </tbody>
</table>

5. Test Permission Changes

Always test permission changes before deploying:

  1. Create test user in each group
  2. Verify they can access what they should
  3. Verify they cannot access what they shouldn't
  4. Test edge cases and workflows

Permission Reference

Complete Permission List

// Access permissions
'accessCp' => Access the Control Panel
'accessCpWhenSystemIsOff' => Access CP when offline
'performUpdates' => Perform Craft and plugin updates

// User permissions
'editUsers' => Edit users
'registerUsers' => Register users
'assignUserPermissions' => Assign user permissions
'assignUserGroups' => Assign users to groups
'administrateUsers' => Administrate users
'deleteUsers' => Delete users

// Entry permissions (per section)
'viewEntries:{sectionHandle}' => View entries
'createEntries:{sectionHandle}' => Create entries
'saveEntries:{sectionHandle}' => Save entries
'deleteEntries:{sectionHandle}' => Delete entries
'publishEntries:{sectionHandle}' => Publish entries
'editPeerEntries:{sectionHandle}' => Edit other authors' entries
'publishPeerEntries:{sectionHandle}' => Publish other authors' entries
'deletePeerEntries:{sectionHandle}' => Delete other authors' entries

// Asset permissions (per volume)
'viewAssets:{volumeHandle}' => View assets
'saveAssetInVolume:{volumeHandle}' => Save assets
'deleteAssetInVolume:{volumeHandle}' => Delete assets
'replaceFilesInVolume:{volumeHandle}' => Replace files
'editImagesInVolume:{volumeHandle}' => Edit images
'createFoldersInVolume:{volumeHandle}' => Create folders

// Category permissions
'viewCategories:{groupHandle}' => View categories
'saveCategories:{groupHandle}' => Save categories
'deleteCategories:{groupHandle}' => Delete categories

// Global permissions
'editGlobalSet:{handle}' => Edit global set

// Utility permissions
'utility:{utilityHandle}' => Access utility

Next Steps

Resources