Permissions¶
There are two main aspects regarding permissions in ECA: permissions required to maintain ECA models, and permissions applied during the execution of those models.
Maintaining ECA models¶
Permissions for creating, editing and managing ECA models are provided by the Modeler API module — a dependency of the ECA UI module. The Modeler API dynamically generates a set of granular permissions for each installed modeler (e.g. BPMN.iO, Workflow Modeler).
The most important permissions are:
modeler api collection eca- View the ECA model collection at
/admin/config/workflow/eca. modeler api view eca- View individual ECA models.
modeler api edit eca- Create, edit, enable, disable, clone, import and export ECA models.
modeler api delete eca- Delete ECA models.
modeler api administer eca- Access the ECA settings page at
/admin/config/workflow/eca/settings. This is a restricted permission.
In addition, there are per-modeler permissions that control which modeler a user may use:
modeler api edit eca with bpmn_io- Edit ECA models with the BPMN.iO modeler.
modeler api view eca with bpmn_io- View ECA models rendered by the BPMN.iO modeler.
Similar permissions are generated for each additional modeler plugin (e.g. workflow_modeler).
Further permissions cover metadata editing, context switching, templates, testing and replay:
modeler api edit metadata eca— Edit model metadata.modeler api switch context eca— Switch the modeler context.modeler api create template eca— Create ECA templates.modeler api edit template eca— Edit ECA templates.modeler api test eca— Test ECA models.modeler api replay eca— Replay ECA models.
Finally, the ECA core module defines one additional permission via its entity type:
administer eca- Full administrative access to ECA configuration entities. This permission is used by the ECA log view and the External Workflows settings page.
User permission when executing models¶
All ECA models are processed under the context of the current user. This means that all conditions and actions respect the permissions of the user who triggered the event.
- Web requests: The model executes with the permissions of the currently logged-in user (or Anonymous if not logged in).
- Cron: Drupal runs cron as the Anonymous user (UID 0). Models triggered by the ECA: Cron event therefore execute without any authenticated session.
- Drush: Commands such as
drush cronordrush eca:trigger:custom_eventrun as Anonymous (UID 0) by default, unless the--uidoption is passed to Drush.
If the current user lacks the necessary permissions to perform an action (e.g. publishing content, viewing a specific entity, or executing a View), that action will fail or return incomplete results.
Global execution user¶
ECA provides a global setting (eca.settings.user) that allows all model executions to run under a specific user account, regardless of who triggered the event. When this setting is configured (via the ECA settings page at /admin/config/workflow/eca/settings):
- Every model execution automatically switches to the configured user before processing begins.
- The original user who triggered the event is available as the
[session_user]token, so your model can still reference or compare against the real user. - After model execution completes, the user context reverts automatically.
This is particularly useful for sites where many models need elevated permissions, avoiding the need to add explicit user-switch actions to every model.
Resolved for every execution as of ECA 3.1.x
Both this setting and the [session_user] token are resolved for every model execution, rather than once per PHP process. This matters wherever a single process runs many executions, such as cron runs, queue workers and Drush commands. Previously [session_user] reported whichever account was current the first time any model ran in that process, and stayed stale for the rest of it. It is now correct for each individual execution.
Changing the setting also takes effect from the next execution, instead of requiring a new process before it is picked up.
Switching user context within a model¶
When only certain parts of a model need elevated permissions, you can switch the user context explicitly. ECA provides three actions for this:
- User: switch current account
- Switch to a specific user by UID. The switch applies only to the successors of this action. Once that branch of the model execution completes, the user context automatically reverts to the previous user. This includes any custom events triggered from within the switched context.
- User: switch to service user
- Switch to the globally configured service user (
eca.settings.service_user), set on the ECA settings page. This works identically to the regular switch but avoids hard-coding a UID into each model. Using a service user is recommended for portability — the same model can work across different environments without modification. - User: switch back
- Explicitly switch back to the previous user account before the current branch completes. This is useful when you need to return to the original user context mid-way through a sequence of actions rather than waiting for the automatic revert at the end of the branch.
Account switching is not permission-gated
ECA does not check any permission before carrying out these switches. Any model that can be triggered can switch to any account, including one with far more privileges than the user who triggered it.
Restricting who may reach those actions is entirely the responsibility of the model author: guard the branch that switches with conditions, for example on the triggering user, their roles, or the context the model runs in. This is long-standing behavior rather than a recent change. It was simply never written down.
Executing Views and queries¶
A common scenario involves using the Views: Execute query action. Views checks entity access permissions by default, which means:
- If the current user (e.g. Anonymous during cron) does not have access to the entities returned by the View, the result set will be empty — even if the entities exist.
- View-level access settings such as "Unrestricted" only control who can run the View, not which entities are returned. Entity-level access checks still apply unless SQL rewriting is explicitly disabled in the View configuration.
Solution: Switch the user context to a privileged account before executing the View. Remember to store the original user in a token first if you need to reference it afterwards.
Example: Querying a View during cron
A model triggered by the ECA cron event needs to load nodes from a View:
- The model starts as Anonymous (UID 0).
- Add a User: switch current account action to switch to a user with the necessary permissions.
- Execute the View — results now include entities the switched user has access to.
- The user context reverts automatically when the branch completes.
If you also need to compare values against the original user, load the current user entity into a token before switching.
Applying recipes¶
As of ECA 3.1.x, the Recipe: apply action requires the executing account to hold the administer site configuration permission. Applying a recipe can install modules and run configuration actions, so it is treated as a site administration task.
ECA treats a denied action as skipped, not as an error. A model that applies a recipe under an account lacking that permission therefore does nothing at all: no error is raised, and the only trace is an access denial written to the log.
Before relying on this action, establish which account the model actually executes as (the triggering user, the global execution user, or an account the model has switched to), and grant administer site configuration to that account.
Multiple models reacting to the same access event¶
When more than one ECA model reacts to the same access event, each model's verdict is combined with the verdicts of the others using a logical OR, instead of the model executed last overwriting the earlier ones. A forbidden result from any reacting model therefore wins, regardless of model weight or execution order.
As of ECA 3.1.x this applies to the ECA Endpoint access event and the Views: Access event as well, bringing them in line with entity access, create access and file download, where it was always the case.
Overriding a verdict by model weight no longer works
The pattern that breaks is override by weight: a low-weight model that forbids broadly, plus a higher-weight model that allows an exception to it. That combination used to grant access, and now forbids it, because the broad denial is no longer overwritten.
Model the exception the other way round instead: let the broad model forbid only when the exception does not apply, or collapse both models into a single model with a condition. None of this matters when only one model reacts to the event.