ACL with Roles and Resources
Understanding how Access Control Lists (ACL) work with roles and resources is essential for securing the admin area and API endpoints.
ACL System Overview
What is ACL (Access Control List)?
Magento uses the Access Control List (ACL) to restrict permissions and control what users can do in the system.
- Admin users - What they can access in the admin panel
- API users - What API endpoints they can call
- Specific actions - Fine-grained permission control
Admin Area Control
ACL determines which admin pages and actions a user can access:
- View specific menu items
- Access certain controllers
- Perform create/edit/delete operations
API Endpoint Control
ACL restricts which API endpoints can be called:
- REST API endpoints
- SOAP API endpoints
- GraphQL mutations/queries
Where ACL is Specified
1. API Endpoints - webapi.xml
ACL for API endpoints (REST/SOAP) is specified in etc/webapi.xml:
<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
<route url="/V1/orders/:id" method="GET">
<service class="Magento\Sales\Api\OrderRepositoryInterface" method="get"/>
<resources>
<resource ref="Magento_Sales::sales_order"/>
</resources>
</route>
</routes>
<resource ref="..."> element specifies which ACL resource is required to access this endpoint.
2. Admin Controllers - Two Methods
For admin routes, ACL is typically embedded directly into the admin controller using one of two methods:
Method 1: ADMIN_RESOURCE Constant
The recommended and most common approach - define a constant in the controller:
<?php
namespace Magento\Cms\Controller\Adminhtml\Page;
use Magento\Backend\App\Action;
use Magento\Framework\App\Action\HttpPostActionInterface;
class Save extends Action implements HttpPostActionInterface
{
/**
* Authorization level of a basic admin session
* @see _isAllowed()
*/
const ADMIN_RESOURCE = 'Magento_Cms::save';
public function execute()
{
// Controller logic here
}
}
- The parent
Actionclass automatically checks this constant - If the user doesn't have permission, access is denied
- Returns a 403 Forbidden response
Reference: See Magento\Cms\Controller\Adminhtml\Page\Save
Method 2: _isAllowed() Method
Override the _isAllowed() method for custom or dynamic permission logic:
<?php
namespace Vendor\Module\Controller\Adminhtml\Entity;
use Magento\Backend\App\Action;
class Delete extends Action
{
/**
* Check if admin has permission to delete
*
* @return bool
*/
protected function _isAllowed()
{
// Custom logic - can check multiple resources or conditions
return $this->_authorization->isAllowed('Vendor_Module::entity_delete');
}
public function execute()
{
// Controller logic here
}
}
- Need to check multiple ACL resources
- Permission logic depends on runtime conditions
- Require custom authorization logic
ADMIN_RESOURCE constant whenever possible. Only override _isAllowed() when you need custom logic.
Defining ACL Resources - acl.xml
To define ACL resources, create an etc/acl.xml configuration file in your module:
acl.xml with at least one resource configured.
How to Add a New ACL Resource
Example: Adding ACL for an order export tool
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<!-- MUST be inside Magento_Backend::admin -->
<resource id="Magento_Backend::admin">
<resource id="Vendor_OrderExport::export"
title="Order Export"
sortOrder="100">
<resource id="Vendor_OrderExport::export_orders"
title="Export Orders"
sortOrder="10"/>
<resource id="Vendor_OrderExport::export_config"
title="Export Configuration"
sortOrder="20"/>
</resource>
</resource>
</resources>
</acl>
</config>
Critical Requirement
You MUST place your ACL structure inside the Magento_Backend::admin resource!
If you omit this, administrators will NOT see your ACL entry in the admin panel, and the entire purpose of using ACL is defeated.
ACL Hierarchy Example
ACL resources can be nested to create a hierarchy:
<resource id="Magento_Backend::admin">
<resource id="Magento_Sales::sales" title="Sales">
<resource id="Magento_Sales::sales_operation" title="Operations">
<resource id="Magento_Sales::sales_order" title="Orders"/>
<resource id="Magento_Sales::sales_invoice" title="Invoices"/>
<resource id="Magento_Sales::shipment" title="Shipments"/>
</resource>
</resource>
</resource>
- Granting access to a parent resource grants access to all child resources
- You can grant access to specific child resources only
- Denying parent denies all children
ACL Resource Naming Conventions
While there are no strict requirements for ACL ID naming, the Magento convention is:
ModuleName::description_of_action
Combine the module's name (as seen in
registration.php) and the description of the action, separated by two colons ::
Examples:
Magento_Cms::save- CMS save operationMagento_Cms::page- CMS page managementMagento_Sales::sales_order- Sales order accessMagento_Catalog::products- Product catalog accessVendor_CustomModule::custom_action- Custom module action
ACL Structure Elements
| Element | Attribute | Description | Required |
|---|---|---|---|
<resource> |
id |
Unique identifier for the ACL resource | ✅ Yes |
title |
Human-readable title shown in admin | ✅ Yes (except for Magento_Backend::admin) | |
sortOrder |
Display order in admin ACL tree | ❌ Optional | |
disabled |
Set to "true" to disable an existing ACL | ❌ Optional |
Managing Existing ACL Hierarchy
Disabling Existing ACL Resources
You can disable an existing ACL entry to prevent it from appearing:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Magento_Cms::save" disabled="true"/>
</resource>
</resources>
</acl>
</config>
ACL in Practice
Complete Example: Product Export Module
Step 1: Define ACL in etc/acl.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Acl/etc/acl.xsd">
<acl>
<resources>
<resource id="Magento_Backend::admin">
<resource id="Vendor_ProductExport::export"
title="Product Export"
sortOrder="100">
<resource id="Vendor_ProductExport::export_action"
title="Export Products"/>
<resource id="Vendor_ProductExport::export_view"
title="View Export History"/>
</resource>
</resource>
</resources>
</acl>
</config>
Step 2: Use in Admin Controller
<?php
namespace Vendor\ProductExport\Controller\Adminhtml\Export;
use Magento\Backend\App\Action;
use Magento\Framework\App\Action\HttpPostActionInterface;
class Execute extends Action implements HttpPostActionInterface
{
const ADMIN_RESOURCE = 'Vendor_ProductExport::export_action';
public function execute()
{
// Export logic here
// Only users with the export_action permission can access this
}
}
Step 3: Use in API (etc/webapi.xml)
<?xml version="1.0"?>
<routes xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Webapi:etc/webapi.xsd">
<route url="/V1/products/export" method="POST">
<service class="Vendor\ProductExport\Api\ExportInterface" method="execute"/>
<resources>
<resource ref="Vendor_ProductExport::export_action"/>
</resources>
</route>
</routes>
Admin Panel ACL Management
Once ACL resources are defined, administrators can manage permissions:
- Create or edit a role
- Go to "Role Resources" tab
- Select "Custom" for Resource Access
- Check/uncheck specific ACL resources
- Save the role
Roles
A role is a collection of resources that can be assigned to users.
- Administrators
- Sales Team
- Customer Service
- Custom roles
Resources
Individual permissions defined in acl.xml files.
- View products
- Edit orders
- Manage customers
- System configuration
ACL XSD Schema
The full specification for acl.xml files can be found in the XSD schema file.
vendor/magento/framework/Acl/etc/acl.xsd
This schema defines all valid elements, attributes, and structure for ACL configuration files.
Common ACL Scenarios
Scenario 1: Order Export
Requirement: Only certain users can export orders
- Create ACL:
Vendor_Module::export_orders - Add to controller:
const ADMIN_RESOURCE = 'Vendor_Module::export_orders'; - Assign to specific admin roles
Scenario 2: Configuration Section
Requirement: Restrict access to module settings
- Create ACL:
Vendor_Module::config - Reference in
system.xmlresource attribute - Assign to administrator roles only
Quick Reference
| Concept | File/Location | Purpose |
|---|---|---|
| Define ACL Resources | etc/acl.xml |
Create new ACL resources for your module |
| API ACL | etc/webapi.xml |
Specify ACL for REST/SOAP endpoints |
| Controller ACL | ADMIN_RESOURCE constant |
Protect admin controller actions |
| Custom ACL Logic | _isAllowed() method |
Custom or dynamic permission checks |
| Parent Resource | Magento_Backend::admin |
Required parent for all admin ACL |
| Naming Convention | ModuleName::action |
Standard ACL ID format |
Exam Tips
Key Points to Remember
- ACL controls both admin users and API users
- API ACL is defined in
etc/webapi.xml - Admin ACL uses
ADMIN_RESOURCEconstant or_isAllowed()method - Every admin module should have an acl.xml
- MUST place ACL inside
Magento_Backend::adminor it won't appear - Naming convention:
ModuleName::action_description - ACL resources are hierarchical - parent access grants child access
- Use
ADMIN_RESOURCEconstant whenever possible (simpler) - Override
_isAllowed()only for custom/dynamic logic - XSD schema location:
Magento/Framework/Acl/etc/acl.xsd - Disabling ACL resources is rarely needed and should be used with caution