On 8 December 2021, the 9.3.0 minor version of Drupal was released, containing, like usual, some progressive enhancements to the overall product. Among these, I would like to highlight today two such changes pertaining the the permissions system. So let’s get to it.
Permissions must exist
Up until 9.3, a user role configuration could contain permissions that no longer existed (i.e that are not defined by any module). And Drupal did not have a problem with it. A common use case of how this can happen is by uninstalling a module which defines certain permissions configured on a role. And, of course, that module not having an uninstall hook to clear those permissions from the existing roles.
Since Drupal 9.3, if a role finds itself containing permissions that are no longer defined by any module, a deprecation error will be triggered. And starting with Drupal 10, a runtime exception. Normally, though, this should not happen, because of the next change we are going to talk about, namely that permissions can now define dependencies.
And not to worry, this change is backwards compatible in the sense that if you have a site with roles that contain inexistent permissions, a core update path will clean up those roles to prevent any notices.
Permissions have dependencies
In order to ensure that role configuration entities only list existing permissions, the latter has now been also given the possibility to define dependencies (both module and config). Typically, the module dependency will be set automatically from the provider of the permission. But when it comes to config dependencies, we need to specifically mark them. Here’s a simple definition example in a permissions file called my_module.permissions.yml
:
my custom permission:
title: 'My custom permission'
description: 'This is a custom permission'
dependencies:
config:
- some_module.some_config_name
In this example, we define a permission and we declare that it depends on the configuration object some_module.some_config_name
. So two new things will happen as a consequence:
- When this permission is added to a role, the role configuration will get the
some_module.some_config_name
as a config dependency and our custommy_module
as a module dependency. - When we uninstall
my_module
or we deletesome_module.some_config_name
, the role configuration will be updated and its permissions list will be recalculated in order to remove the ones that no longer exist.
This way we ensure that roles no longer are saved with invalid permissions.
But what about permissions defined dynamically via a permissions callback? Well, it’s the same thing, but we need to include these dependency structures inside a PHP array. A common use case for this is dynamically defining permissions based on entity bundles, like Node does, for example, in Drupal\node\NodePermissions
. For these use cases we get a helpful BundlePermissionHandlerTrait
that we can use to apply the dependency information on the resulting permissions array. Check out NodePermissions
for a better understanding of how this trait should be used.
And that’s pretty much it. Now we have a closer tie between roles and permissions. You can read the related change records here:
Hope this helps.

Daniel Sipos
Danny founded WEBOMELETTE in 2012 as a passion project, mostly writing about Drupal problems he faced day to day, as well as about new technologies and things that he thought other developers would find useful. Now he now manages a team of developers and designers, delivering quality products that make businesses successful.
Comments
How to remove uninstalled permissions?
I uninstalled Mailchimp, and it left permissions behind. That stops upgrading to D10. How do I deelete them?
Permissions of user role: "officer":
entity print access type mailchimp_campaign
In reply to How to remove uninstalled permissions? by Jim Rome (not verified)
edit config yml for role
if you edit the config yml file for the roles (i.e. user.role.my_role.yml), search for the lines containing the permissions relating to Mailchimp, delete those lines, save the yml file, then run
drush cim
to re-import the permissions. This will delete all the permissions from active config.Add new comment