2.01

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.

Why This Matters: ACL (Access Control List) is essential for securing the admin area and API endpoints. Understanding how to configure ACL properly ensures that only authorized users can access specific features and functionality.

ACL System Overview

mindmap root((ACL System)) Purpose Restrict Admin Users Restrict API Users Permission Management Configuration etc/acl.xml etc/webapi.xml Admin Controllers Implementation ADMIN_RESOURCE _isAllowed method ACL Hierarchy Structure Roles Resources Magento_Backend::admin Management Add Resources Disable Resources Naming Conventions

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.

ACL Controls:
  • 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

etc/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>
The <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
    }
}
How it works:
  • The parent Action class 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
    }
}
When to use _isAllowed():
  • Need to check multiple ACL resources
  • Permission logic depends on runtime conditions
  • Require custom authorization logic
Best Practice: Use ADMIN_RESOURCE constant whenever possible. Only override _isAllowed() when you need custom logic.

Defining ACL Resources - acl.xml

etc/acl.xml

To define ACL resources, create an etc/acl.xml configuration file in your module:

⚠️ Critical Requirement: Every module that adds admin functionality should have an 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>
Hierarchy Behavior:
  • 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:

Convention: 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 operation
  • Magento_Cms::page - CMS page management
  • Magento_Sales::sales_order - Sales order access
  • Magento_Catalog::products - Product catalog access
  • Vendor_CustomModule::custom_action - Custom module action
Best Practice: Always follow this naming convention for consistency and clarity. It makes ACL resources easy to identify and understand.

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>
⚠️ Use with Caution: Disabling ACL resources is rarely needed and can break functionality. This should only be used in very specific customization scenarios.

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:

Admin Path: System → Permissions → User Roles
  • 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

Magento/Framework/Acl/etc/acl.xsd

The full specification for acl.xml files can be found in the XSD schema file.

Key XSD Location:
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

Solution:
  1. Create ACL: Vendor_Module::export_orders
  2. Add to controller: const ADMIN_RESOURCE = 'Vendor_Module::export_orders';
  3. Assign to specific admin roles

Scenario 2: Configuration Section

Requirement: Restrict access to module settings

Solution:
  1. Create ACL: Vendor_Module::config
  2. Reference in system.xml resource attribute
  3. 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_RESOURCE constant or _isAllowed() method
  • Every admin module should have an acl.xml
  • MUST place ACL inside Magento_Backend::admin or it won't appear
  • Naming convention: ModuleName::action_description
  • ACL resources are hierarchical - parent access grants child access
  • Use ADMIN_RESOURCE constant 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

Further Reading