Overview
Drupal's role-based access control (RBAC) system provides granular permission management through roles. This guide covers creating custom roles, assigning permissions, and implementing best practices for user access control.
Understanding Drupal's Permission System
How Permissions Work
Permission Hierarchy:
User → Assigned Roles → Inherited Permissions
Key Principles:
- Permissions are additive (users get all permissions from all their roles)
- Permissions are module-specific (each module defines its own permissions)
- Deny never overrides allow (if any role grants permission, user has it)
- User 1 (UID 1) bypasses all permission checks
Permission Types
1. Content Permissions:
- View published/unpublished content
- Create content types
- Edit own/any content
- Delete own/any content
- Revert revisions
2. Administration Permissions:
- Administer site configuration
- Administer users
- Administer permissions
- Administer modules
- Administer themes
3. Module-Specific Permissions:
- Administer blocks
- Administer views
- Administer taxonomy
- Administer commerce products
- Administer webforms
Managing Roles
Accessing Role Management
Navigate to: Admin → People → Roles (/admin/people/roles)
Required permission: Administer permissions
Default Roles
1. Anonymous User
- Non-authenticated visitors
- Default permissions: View published content
- Cannot be deleted
2. Authenticated User
- Any logged-in user
- Base permissions for all authenticated users
- Cannot be deleted
3. Administrator
- Full site access
- Created during installation
- Can be deleted (but not recommended)
Creating Custom Roles
Via UI:
- Navigate to
/admin/people/roles - Click Add role
- Enter role name (e.g., "Content Editor")
- Optionally set role weight (affects display order)
- Click Save
Via Drush:
# Create role
drush role:create content_editor "Content Editor"
# Create role with specific machine name
drush role:create marketing_manager "Marketing Manager"
# List all roles
drush role:list
Programmatically:
<?php
use Drupal\user\Entity\Role;
// Create role
$role = Role::create([
'id' => 'content_editor',
'label' => 'Content Editor',
'weight' => 3,
]);
$role->save();
Role Naming Best Practices
Good Names:
- Content Editor
- Site Manager
- Marketing Manager
- Support Staff
- Product Manager
Avoid:
- ✗ Editor (too vague)
- ✗ User (confusing)
- ✗ Admin2 (unclear purpose)
Assigning Permissions
Permission Configuration
Navigate to: Admin → People → Permissions (/admin/people/permissions)
Interface Overview:
- Rows: Individual permissions
- Columns: Roles
- Checkboxes: Grant permission to role
Common Permission Patterns
Content Creator Role
Minimal permissions for creating content:
Content:
☑ Article: Create new content
☑ Article: Edit own content
☑ Article: Delete own content
☑ View published content
☑ View own unpublished content
Media:
☑ Create media
Toolbar:
☑ Use the toolbar
Content Editor Role
Full content management without admin access:
Content:
☑ Article: Create new content
☑ Article: Edit any content
☑ Article: Delete any content
☑ Article: Revert revisions
☑ Page: Create new content
☑ Page: Edit any content
☑ View published content
☑ View unpublished content
Media:
☑ Create media
☑ Edit media
☑ Delete media
Taxonomy:
☑ Create terms in [vocabulary]
☑ Edit terms in [vocabulary]
System:
☑ Use the administration pages and help
☑ View the administration theme
Site Manager Role
Administrative permissions without development access:
All Content Editor permissions, plus:
Blocks:
☑ Administer blocks
Menus:
☑ Administer menus and menu items
Users:
☑ Administer users (with caution)
☑ Assign roles (with caution)
Views:
☑ Administer views
Webforms:
☑ Administer webforms
System:
☑ Administer site configuration (with caution)
Developer Role
Technical permissions:
All Site Manager permissions, plus:
Modules:
☑ Administer modules
Themes:
☑ Administer themes
Configuration:
☑ Synchronize configuration
☑ Export configuration
☑ Import configuration
Views:
☑ Administer views
☑ Use PHP in views (security risk - use carefully)
Development:
☑ Access developer information
☑ Access Devel information
Files:
☑ Administer file settings
Managing Permissions via Code
Export Permissions Configuration
# Export all configuration
drush config:export -y
# Check user role configuration
cat config/sync/user.role.content_editor.yml
Example: user.role.content_editor.yml
langcode: en
status: true
dependencies: { }
id: content_editor
label: 'Content Editor'
weight: 3
is_admin: false
permissions:
- 'access content'
- 'create article content'
- 'edit own article content'
- 'delete own article content'
- 'create page content'
- 'edit any page content'
- 'access toolbar'
- 'access user profiles'
Assign Permissions Programmatically
<?php
use Drupal\user\Entity\Role;
// Load role
$role = Role::load('content_editor');
// Grant permissions
$role->grantPermission('create article content');
$role->grantPermission('edit own article content');
$role->save();
// Revoke permissions
$role->revokePermission('delete any article content');
$role->save();
// Check if role has permission
if ($role->hasPermission('edit own article content')) {
// Role has permission
}
// Get all permissions for role
$permissions = $role->getPermissions();
Bulk Permission Assignment
<?php
use Drupal\user\Entity\Role;
$role = Role::load('content_editor');
$permissions = [
'access content',
'create article content',
'edit own article content',
'delete own article content',
'access toolbar',
'use text format basic_html',
];
foreach ($permissions as $permission) {
$role->grantPermission($permission);
}
$role->save();
Assigning Roles to Users
Via User Interface
Method 1: Edit individual user
- Navigate to
/admin/people - Click Edit next to user
- Check desired roles under Roles section
- Click Save
Method 2: Bulk operations
- Navigate to
/admin/people - Select multiple users (checkboxes)
- Choose action: Add the [role] role to selected users
- Click Apply to selected items
Via Drush
# Add role to user
drush user:role:add "content_editor" johndoe
# Remove role from user
drush user:role:remove "content_editor" johndoe
# Add role to multiple users
drush user:role:add "editor" johndoe,janedoe,bobsmith
Programmatically
<?php
use Drupal\user\Entity\User;
// Load user
$user = User::load(123);
// Add role
$user->addRole('content_editor');
$user->save();
// Remove role
$user->removeRole('content_editor');
$user->save();
// Check if user has role
if ($user->hasRole('content_editor')) {
// User has content editor role
}
// Get all user roles
$roles = $user->getRoles();
// Get roles excluding 'authenticated'
$roles = $user->getRoles(TRUE);
Content Access Control
Content Type Permissions
Each content type has its own permissions:
[Content Type]: Create new content
[Content Type]: Edit own content
[Content Type]: Edit any content
[Content Type]: Delete own content
[Content Type]: Delete any content
[Content Type]: Delete revisions
[Content Type]: Revert revisions
[Content Type]: View revisions
Node Access Modules
For more granular control:
Content Access Module:
composer require drupal/content_access
drush en content_access -y
Features:
- Per-content type permissions
- Per-node permissions
- Role-based node access
Permissions per content type:
Navigate to: /admin/structure/types/manage/[type]/access
Group Module:
composer require drupal/group
drush en group -y
Features:
- Organizational groups
- Group content ownership
- Group-specific roles
Field-Level Permissions
Field Permissions Module
composer require drupal/field_permissions
drush en field_permissions -y
Configure per field:
Navigate to: /admin/structure/types/manage/[type]/fields/[field]/storage
Permission types:
- Public (everyone can view/edit)
- Private (only author and administrators)
- Custom (define specific roles)
Example use cases:
- Internal notes field (admin only)
- Draft comments (author only)
- Sensitive data (specific roles)
Taxonomy Permissions
Per-Vocabulary Permissions
[Vocabulary]: Create terms
[Vocabulary]: Edit terms
[Vocabulary]: Delete terms
Taxonomy Access Control
composer require drupal/taxonomy_access_fix
drush en taxonomy_access_fix -y
Or for more control:
composer require drupal/tac_lite
drush en tac_lite -y
Testing Permissions
Masquerade as Another User
Install Masquerade module:
composer require drupal/masquerade
drush en masquerade -y
Usage:
- Navigate to
/admin/people - Click Masquerade as link next to user
- Test permissions as that user
- Click Stop masquerading to return
Or via Drush:
# Generate one-time login link for user
drush user:login johndoe
Permission Audit
Check user's permissions:
<?php
$current_user = \Drupal::currentUser();
// Check specific permission
if ($current_user->hasPermission('edit any article content')) {
// User can edit articles
}
// Get all user permissions (expensive operation)
$permissions = $current_user->getPermissions();
List all permissions for role:
# Via Drush (custom command needed)
drush role:list --format=json | jq '.content_editor.permissions'
Security Best Practices
Principle of Least Privilege
Grant only the minimum permissions needed:
Good:
- Content Creator: Create/edit own articles only
- Site Editor: Edit content but not users
- Marketing Manager: Manage content and taxonomy, not configuration
✗ Bad:
- Giving everyone administrator role
- Granting "Administer site configuration" broadly
- Allowing untrusted users to use PHP filter
Dangerous Permissions
Use with extreme caution:
☐ Administer modules (can install malicious code)
☐ Administer permissions (can grant themselves any permission)
☐ Administer users (can create admin accounts)
☐ Synchronize configuration (can import malicious config)
☐ Use PHP for settings (arbitrary code execution)
☐ Bypass content access control (see all content)
Alternative approaches:
- Create specific administrative roles
- Use workflow modules instead of admin access
- Implement approval processes
- Regular permission audits
Permission Auditing
Regular checks:
# Export current permissions
drush config:export -y
# Review user.role.*.yml files
cat config/sync/user.role.*.yml
# Check for overprivileged roles
grep -r "is_admin: true" config/sync/
Automated monitoring:
<?php
/**
* Implements hook_cron().
*/
function mymodule_cron() {
// Check for users with dangerous permissions
$dangerous_permissions = [
'administer modules',
'administer permissions',
'use PHP for settings',
];
foreach ($dangerous_permissions as $permission) {
$accounts = \Drupal::entityTypeManager()
->getStorage('user')
->loadByProperties();
foreach ($accounts as $account) {
if ($account->hasPermission($permission)) {
// Log or alert
\Drupal::logger('security')->warning('User @user has dangerous permission: @perm', [
'@user' => $account->getAccountName(),
'@perm' => $permission,
]);
}
}
}
}
Advanced Permission Scenarios
Content Workflow Permissions
Using Workflows module:
composer require drupal/workflows
drush en workflows content_moderation -y
Configure:
- Create workflow (Draft → Review → Published)
- Assign workflow to content types
- Create roles for each stage:
- Content Creator: Create draft
- Reviewer: Move draft to review
- Publisher: Publish reviewed content
Navigate to: /admin/config/workflow/workflows
Time-Based Permissions
Scheduler module:
composer require drupal/scheduler
drush en scheduler -y
Permissions:
☑ Schedule content for publication
☑ Schedule content for unpublication
Organic Groups / Group Permissions
composer require drupal/group
drush en group -y
Features:
- Create groups (teams, projects, departments)
- Group-specific content
- Group-specific roles (group admin, group member)
- Inherit global roles
Troubleshooting Permissions
User Can't See Content
Check:
- User has "View published content" permission
- Content is published (status = 1)
- User has permission for that content type
- No node access modules blocking access
User Can't Edit Content
Check:
- User has "Edit own" or "Edit any" permission
- User is owner (for "edit own")
- Content is not locked by another user
- Field-level permissions aren't restricting
Permission Changes Not Taking Effect
Solutions:
# Clear all caches
drush cr
# Rebuild permissions
drush php:eval "node_access_rebuild();"
# Check configuration
drush config:export -y
Migration & Deployment
Exporting Permission Configuration
# Export all configuration
drush config:export -y
# Commit configuration to git
git add config/sync/user.role.*.yml
git commit -m "Update role permissions"
git push
Importing on Production
# Pull latest code
git pull
# Import configuration
drush config:import -y
# Clear cache
drush cr
# Verify
drush role:list
Resources
Next Steps
Quick Reference
Essential Drush Commands
# Role management
drush role:create MACHINE_NAME "Human Name"
drush role:list
# Assign roles
drush user:role:add "ROLE" USERNAME
drush user:role:remove "ROLE" USERNAME
# Permission operations
drush config:get user.role.ROLE permissions
drush config:set user.role.ROLE permissions.X "permission name"
# Export/Import
drush config:export -y
drush config:import -y
Common Permission Sets
View-only access:
☑ Access content
☑ Use the toolbar
Basic content creator:
☑ Access content
☑ Create article content
☑ Edit own article content
☑ Use text format basic_html
☑ Use the toolbar
Full content editor:
☑ Access content
☑ Create/Edit/Delete any article/page content
☑ Administer taxonomy
☑ Create/Edit media
☑ Use text format full_html
☑ Use the administration pages