Permissions are one of the most important—and often misunderstood—parts of Drupal. Every serious Drupal site relies on permissions to control access to admin pages, actions, configuration, and content. Whether you are a junior developer learning Drupal or a senior engineer designing enterprise systems, understanding permissions deeply will make your code more secure, predictable, and maintainable.
This article takes a deep dive into how Drupal permissions actually work, from simple YAML definitions to the internal role of PermissionHandler. The goal is clarity, not shortcuts.
Why Permissions Matter in Real Drupal Projects
Drupal does not grant access based on roles. It grants access based on permissions.
Roles are just containers. Permissions are the real decision-makers.
This design allows Drupal to:
- Scale access control across large teams
- Avoid hardcoding logic
- Support flexible, future-proof authorization
- Keep security decisions centralized
If permissions are poorly designed early, projects suffer later—especially during deployments, audits, and team growth.
How Drupal Thinks About Permissions
A permission in Drupal is:
- A named capability
- Assigned to roles
- Checked during access decisions
Examples:
administer usersaccess contentadminister site configuration
Drupal never checks:
"Is this user an administrator?"
It always checks:
"Does this user have permission X?"
This distinction is critical.
Defining Permissions with .permissions.yml
The most common way to define permissions is with a module-level YAML file:
my_module.permissions.yml
Each permission is declared using a machine name as the key.
Basic Example
administer example settings:
title: 'Administer example settings'
description: 'Manage configuration for the Example module.'
restrict access: true
Key Fields Explained
- Machine name
- Used everywhere in code
- Must be stable
- Changing it is a breaking change
- title
- Displayed on the Permissions UI
- Human-readable and clear
- description (optional)
- Explains impact to site builders and admins
- restrict access (optional)
- Shows a security warning
- Use for powerful or destructive actions
Using Permissions in Code
Permissions are referenced by their machine name.
Route Access Example
example.settings:
path: '/admin/config/example'
defaults:
_controller: '\Drupal\example\Controller\ExampleController::settings'
_title: 'Example settings'
requirements:
_permission: 'administer example settings'
Controller Access Example
if (!$this->currentUser()->hasPermission('administer example settings')) {
throw new AccessDeniedHttpException();
}
This keeps access logic explicit and testable.
Dynamic Permissions with permission_callbacks
Not all permissions can be defined statically.
Common cases:
- Permissions per entity bundle
- Permissions per text format
- Permissions based on configuration
Drupal supports this through permission callbacks.
Example
permission_callbacks:
- Drupal\example\ExamplePermissions::permissions
Callback Implementation
class ExamplePermissions {
public static function permissions() {
return [
'edit special content' => [
'title' => 'Edit special content',
'description' => 'Edit content marked as special.',
],
];
}
}
The callback returns the same structure as static permissions.
What PermissionHandler Does (Internals)
The PermissionHandler class is responsible for discovering and assembling all permissions in the system.
Conceptually, it:
- Finds all
.permissions.ymlfiles - Loads static permission definitions
- Executes permission callbacks
- Merges results
- Sorts permissions by provider and title
- Translates labels for the UI
This process ensures that permissions are:
- Modular
- Cacheable
- Discoverable
- Consistent
Most developers never call PermissionHandler directly—but every permission relies on it.
Permissions, Roles, and Users
The relationship is simple:
- Permissions define capabilities
- Roles group permissions
- Users are assigned roles
- Access checks evaluate permissions
This separation allows:
- Safer refactoring
- Cleaner deployments
- Easier audits
- Better collaboration between devs and admins
Common Mistakes to Avoid
- Checking roles instead of permissions
- Reusing unrelated core permissions
- Creating overly broad permissions
- Mixing configuration and access logic
- Hardcoding admin-only checks
These shortcuts always cause problems later.
How Senior Drupal Developers Use Permissions
Experienced Drupal developers:
- Create granular, descriptive permissions
- Use
restrict accessintentionally - Combine permissions with services and access handlers
- Keep authorization logic explicit
- Design permissions as part of system architecture
Permissions are not an afterthought—they are part of design.
Why This Topic Matters Beyond Level 0
This is not just a beginner topic.
Permissions connect directly to:
- Security reviews
- Enterprise compliance
- Multisite architectures
- API access control
- Custom entity systems
Understanding permissions deeply is a Level 2+ skill that separates casual Drupal developers from confident backend engineers.
Final Takeaway
Drupal’s permission system is powerful because it is:
- Declarative
- Extensible
- Centralized
- Predictable
Once you understand how permissions flow from YAML to PermissionHandler to access checks, Drupal’s access model becomes clear instead of mysterious.
This clarity pays off on every serious Drupal project you build.