Magento 2 User Roles and Permissions | OpsBlu Docs

Magento 2 User Roles and Permissions

How to create custom admin roles and configure granular permissions in Magento 2. Covers ACL resource hierarchy, role scoping, API permissions, and...

Magento 2's role-based access control (RBAC) system uses Access Control Lists (ACL) to define granular permissions for admin users. This guide covers creating custom roles, configuring permissions, understanding resource hierarchies, and implementing advanced ACL configurations.


Understanding Magento ACL

ACL Architecture

Access Control List (ACL) defines which resources a role can access.

Key Components:

  1. Resources: System features and functions (catalogs, orders, reports)
  2. Roles: Named permission sets assigned to users
  3. Rules: Allow/deny permissions for specific resources
  4. Scope: Global, website, or store view level access

Permission Inheritance

Permissions follow a hierarchical structure:

Magento_Backend::admin (Root)
├── Magento_Sales::sales (Sales)
│   ├── Magento_Sales::sales_order (Orders)
│   │   ├── Magento_Sales::actions (Actions)
│   │   ├── Magento_Sales::create (Create)
│   │   └── Magento_Sales::cancel (Cancel)
│   ├── Magento_Sales::sales_invoice (Invoices)
│   └── Magento_Sales::sales_shipment (Shipments)
├── Magento_Catalog::catalog (Catalog)
│   ├── Magento_Catalog::products (Products)
│   └── Magento_Catalog::categories (Categories)
└── Magento_Customer::customer (Customers)

Inheritance Rules:

  • Granting parent permission grants all child permissions
  • Denying parent permission denies all child permissions
  • Child permissions can be individually managed

Creating Custom Roles

Via Admin Panel

1. Navigate to Roles:

System > Permissions > User Roles > Add New Role

2. Role Information Tab:

Required Fields:

  • Role Name: Descriptive name (e.g., "Marketing Manager", "Catalog Editor")
  • Your Password: Current admin password for verification

3. Role Resources Tab:

Resource Access Options:

  • All: Full access to all resources (not recommended except for administrators)
  • Custom: Select specific resources

4. Configure Permissions:

For Marketing Manager:

  • Content
    • Pages
    • Blocks
    • Widgets
  • Marketing
    • Promotions
    • Email Templates
    • SEO & Search
  • Reports
    • Marketing Reports
  • System
  • Stores

5. Save Role:

  • Click "Save Role"
  • Role appears in roles grid

Via Database (Advanced)

Create role programmatically:

<?php
use Magento\Authorization\Model\RoleFactory;
use Magento\Authorization\Model\RulesFactory;

class RoleCreator
{
    protected $roleFactory;
    protected $rulesFactory;

    public function __construct(
        RoleFactory $roleFactory,
        RulesFactory $rulesFactory
    ) {
        $this->roleFactory = $roleFactory;
        $this->rulesFactory = $rulesFactory;
    }

    public function createRole($roleName, $resources)
    {
        // Create role
        $role = $this->roleFactory->create();
        $role->setName($roleName)
            ->setPid(0)  // Parent ID (0 = root)
            ->setRoleType('G')  // G = Group
            ->setUserType(2);  // 2 = Administrator
        $role->save();

        // Set permissions
        $rules = $this->rulesFactory->create();
        $rules->setRoleId($role->getId())
            ->setResources($resources)
            ->saveRel();

        return $role;
    }
}

// Usage
$resources = [
    'Magento_Catalog::catalog',
    'Magento_Catalog::products',
    'Magento_Catalog::categories'
];
$roleCreator->createRole('Catalog Manager', $resources);

Resource Permissions

Core Resource Groups

1. Dashboard

Magento_Backend::dashboard
  • View admin dashboard
  • Sales statistics
  • Best sellers
  • Last orders

2. Sales

Magento_Sales::sales
├── Magento_Sales::sales_order
│   ├── Magento_Sales::actions (View, Edit, Create, Delete)
│   ├── Magento_Sales::create
│   ├── Magento_Sales::actions_view
│   ├── Magento_Sales::actions_edit
│   ├── Magento_Sales::email
│   ├── Magento_Sales::reorder
│   ├── Magento_Sales::cancel
│   ├── Magento_Sales::hold
│   └── Magento_Sales::unhold
├── Magento_Sales::sales_invoice
├── Magento_Sales::sales_shipment
├── Magento_Sales::sales_creditmemo
└── Magento_Sales::transactions

3. Catalog

Magento_Catalog::catalog
├── Magento_Catalog::products
├── Magento_Catalog::categories
├── Magento_Catalog::inventory
│   └── Magento_Catalog::products (Manage Stock)
└── Magento_Catalog::update_attributes

4. Customers

Magento_Customer::customer
├── Magento_Customer::manage
├── Magento_Customer::actions
│   ├── Magento_Customer::create
│   ├── Magento_Customer::edit
│   ├── Magento_Customer::delete
│   └── Magento_Customer::view
├── Magento_Customer::group
└── Magento_Customer::online

5. Marketing

Magento_Backend::marketing
├── Magento_CatalogRule::promo (Catalog Price Rules)
├── Magento_SalesRule::quote (Cart Price Rules)
├── Magento_Email::template
├── Magento_Newsletter::template
├── Magento_Review::reviews_all
└── Magento_Search::search

6. Content

Magento_Backend::content
├── Magento_Cms::page
├── Magento_Cms::block
├── Magento_Widget::widget_instance
├── Magento_Theme::design_configuration
└── Magento_PageBuilder::template (Page Builder)

7. Reports

Magento_Reports::report
├── Magento_Reports::salesroot (Sales Reports)
├── Magento_Reports::product (Products Reports)
├── Magento_Reports::customers (Customers Reports)
├── Magento_Reports::marketing (Marketing Reports)
└── Magento_Reports::search (Search Terms)

8. Stores

Magento_Backend::stores
├── Magento_Backend::stores_settings
│   ├── Magento_Config::config (Configuration)
│   ├── Magento_Store::store (Stores)
│   ├── Magento_Config::config_general
│   └── Magento_Tax::manage_tax
├── Magento_Backend::stores_attributes
│   ├── Magento_Catalog::attributes_attributes
│   └── Magento_Catalog::sets
└── Magento_Backend::stores_other_settings

9. System

Magento_Backend::system
├── Magento_Backend::cache
├── Magento_Indexer::index
├── Magento_Backend::tools
├── Magento_User::acl (Permissions)
│   ├── Magento_User::acl_roles (Roles)
│   └── Magento_User::acl_users (Users)
└── Magento_Integration::integrations

Common Role Configurations

Marketing Manager Role

Permissions:

Dashboard
Marketing
   Promotions (Cart Price Rules, Catalog Price Rules)
   Email Templates
   Newsletter Templates
   SEO & Search
Content
   Pages
   Blocks
   Widgets
   Design Configuration
Reports
   Marketing Reports
   Sales Reports (Read-only)
Customers (Read-only)
   View Customers
   Edit/Delete Customers
System
Stores Configuration

ACL Resources:

$resources = [
    'Magento_Backend::dashboard',
    'Magento_Backend::marketing',
    'Magento_CatalogRule::promo',
    'Magento_SalesRule::quote',
    'Magento_Email::template',
    'Magento_Newsletter::template',
    'Magento_Search::search',
    'Magento_Backend::content',
    'Magento_Cms::page',
    'Magento_Cms::block',
    'Magento_Widget::widget_instance',
    'Magento_Theme::design_configuration',
    'Magento_Reports::report',
    'Magento_Reports::marketing',
    'Magento_Reports::salesroot',
    'Magento_Customer::customer',
    'Magento_Customer::actions_view'
];

Catalog Manager Role

Permissions:

Dashboard
Catalog
   Products (Create, Edit, Delete)
   Categories
   Inventory
   Product Attributes
   Attribute Sets
Reports
   Products Reports
   Inventory Reports
Pricing (Optional restriction)
Sales
System

ACL Resources:

$resources = [
    'Magento_Backend::dashboard',
    'Magento_Catalog::catalog',
    'Magento_Catalog::products',
    'Magento_Catalog::categories',
    'Magento_Catalog::inventory',
    'Magento_Catalog::attributes_attributes',
    'Magento_Catalog::sets',
    'Magento_Reports::product'
];

Customer Service Role

Permissions:

Dashboard
Sales
   Orders (View, Edit, Cancel, Hold)
   Invoices
   Shipments
   Credit Memos
Customers
   All Customers (View, Edit)
   Customer Groups
Reports
   Sales Reports
   Customer Reports
Catalog
System
Pricing Rules

ACL Resources:

$resources = [
    'Magento_Backend::dashboard',
    'Magento_Sales::sales',
    'Magento_Sales::sales_order',
    'Magento_Sales::actions_view',
    'Magento_Sales::actions_edit',
    'Magento_Sales::email',
    'Magento_Sales::cancel',
    'Magento_Sales::hold',
    'Magento_Sales::sales_invoice',
    'Magento_Sales::sales_shipment',
    'Magento_Sales::sales_creditmemo',
    'Magento_Customer::customer',
    'Magento_Customer::manage',
    'Magento_Customer::actions',
    'Magento_Reports::salesroot',
    'Magento_Reports::customers'
];

Content Editor Role

Permissions:

Dashboard
Content
   Pages (Create, Edit, Delete)
   Blocks
   Widgets
   Page Builder Templates
Design
   Themes
   Design Configuration
Catalog
Sales
Customers
System

ACL Resources:

$resources = [
    'Magento_Backend::dashboard',
    'Magento_Backend::content',
    'Magento_Cms::page',
    'Magento_Cms::block',
    'Magento_Widget::widget_instance',
    'Magento_PageBuilder::template',
    'Magento_Theme::design_configuration'
];

Reports/Analytics Role (Read-Only)

Permissions:

Dashboard
Reports (All - Read Only)
   Sales Reports
   Products Reports
   Customers Reports
   Marketing Reports
Customers (View Only)
Sales (View Only)
Catalog (View Only)
Any Write Operations
System
Configuration

Advanced Permission Scenarios

Website/Store Scope Permissions

Restrict users to specific websites in multi-site setup.

Configuration:

System > Permissions > User Roles > [Role] > Role Resources > GWS Scope

Options:

  • All Websites: Access all sites
  • Specific Websites: Select websites
  • Default Store View: Limit to specific store view

Database Implementation:

public function setWebsiteScope($roleId, $websiteIds)
{
    $rule = $this->rulesFactory->create();
    $rule->setRoleId($roleId)
        ->setResources(['Magento_Backend::all'])
        ->setWebsiteIds($websiteIds)  // Array of website IDs
        ->saveRel();
}

Time-Based Permissions

Implement temporary elevated access (requires custom module).

Custom ACL with expiration:

<?php
namespace Vendor\Module\Plugin;

use Magento\Framework\Authorization;

class TemporaryPermissions
{
    public function afterIsAllowed(
        Authorization $subject,
        $result,
        $resource,
        $privilege = null
    ) {
        // Check if user has time-limited permission
        $expiration = $this->getPermissionExpiration($resource);

        if ($expiration && time() > $expiration) {
            return false;  // Permission expired
        }

        return $result;
    }

    protected function getPermissionExpiration($resource)
    {
        // Retrieve from custom table
        // Return timestamp or null
    }
}

API-Only Roles

Create roles specifically for API access.

Integration Permissions:

System > Extensions > Integrations > Add New Integration

Set API Resources:

  • Same ACL structure as admin roles
  • OAuth-based authentication
  • Token-based access

Example:

// Create integration with specific permissions
$integration = $this->integrationFactory->create();
$integration->setName('Third-Party Integration')
    ->setEmail('api@partner.com')
    ->setStatus(1);
$integration->save();

// Set permissions
$this->authorizationService->grantPermissions(
    $integration->getId(),
    [
        'Magento_Catalog::products',
        'Magento_Sales::sales_order'
    ]
);

Custom ACL Resources

Defining Custom Resources

File: app/code/Vendor/Module/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">
                <!-- Main resource group -->
                <resource id="Vendor_Module::main" title="My Module" sortOrder="100">

                    <!-- Sub-resource: Manage -->
                    <resource id="Vendor_Module::manage" title="Manage Items" sortOrder="10">
                        <resource id="Vendor_Module::create" title="Create" sortOrder="10"/>
                        <resource id="Vendor_Module::edit" title="Edit" sortOrder="20"/>
                        <resource id="Vendor_Module::delete" title="Delete" sortOrder="30"/>
                    </resource>

                    <!-- Sub-resource: View -->
                    <resource id="Vendor_Module::view" title="View Items" sortOrder="20"/>

                    <!-- Sub-resource: Reports -->
                    <resource id="Vendor_Module::reports" title="View Reports" sortOrder="30"/>

                    <!-- Sub-resource: Configuration -->
                    <resource id="Vendor_Module::config" title="Configuration" sortOrder="40"/>

                </resource>
            </resource>
        </resources>
    </acl>
</config>

Checking Permissions in Code

Controller:

<?php
namespace Vendor\Module\Controller\Adminhtml\Item;

use Magento\Backend\App\Action;

class Edit extends Action
{
    const ADMIN_RESOURCE = 'Vendor_Module::edit';

    public function execute()
    {
        // Automatic ACL check based on ADMIN_RESOURCE constant
        // If permission denied, user redirected to access denied page
    }
}

Block:

<?php
namespace Vendor\Module\Block\Adminhtml;

use Magento\Backend\Block\Template;
use Magento\Framework\AuthorizationInterface;

class Items extends Template
{
    protected $authorization;

    public function __construct(
        Template\Context $context,
        AuthorizationInterface $authorization,
        array $data = []
    ) {
        $this->authorization = $authorization;
        parent::__construct($context, $data);
    }

    public function canEdit()
    {
        return $this->authorization->isAllowed('Vendor_Module::edit');
    }

    public function canDelete()
    {
        return $this->authorization->isAllowed('Vendor_Module::delete');
    }
}

Template:

<?php if ($block->canEdit()): ?>
    <button>Edit</button>
<?php endif; ?>

<?php if ($block->canDelete()): ?>
    <button>Delete</button>
<?php endif; ?>

Permission Testing

Test Role Permissions

1. Create Test User:

php bin/magento admin:user:create \
    --admin-user="test_marketing" \
    --admin-password="Test123!" \
    --admin-email="test@example.com" \
    --admin-firstname="Test" \
    --admin-lastname="Marketing"

2. Assign Role:

  • System > Permissions > All Users
  • Edit test user
  • Assign "Marketing Manager" role

3. Login as Test User:

  • Logout current admin
  • Login with test credentials
  • Verify accessible/restricted areas

4. Document Results:

  • Can access: Dashboard, Content, Marketing
  • Cannot access: System, Stores, Configuration
  • Expected behavior confirmed

Troubleshooting

Permission Denied Errors

Issue: User sees "Access Denied" despite role assignment

Solutions:

  1. Clear ACL cache:

    php bin/magento cache:clean config
    php bin/magento cache:flush
    
  2. Verify role assignment:

    SELECT u.username, r.role_name
    FROM admin_user u
    JOIN authorization_role r ON u.user_id = r.user_id
    WHERE u.username = 'username';
    
  3. Check resource exists:

    grep -r "Vendor_Module::resource" app/code/
    
  4. Rebuild ACL:

    php bin/magento setup:upgrade
    php bin/magento cache:flush
    

Inherited Permissions Not Working

Issue: Child permissions not inherited from parent

Solution: Verify ACL hierarchy in etc/acl.xml:

  • Ensure proper nesting
  • Check resource IDs match
  • Verify sortOrder values

Best Practices

  1. Principle of Least Privilege: Grant minimum necessary permissions
  2. Regular Audits: Review roles quarterly
  3. Descriptive Names: Use clear, descriptive role names
  4. Documentation: Document custom roles and purposes
  5. Test Thoroughly: Test new roles before production deployment
  6. Avoid "All" Permission: Create custom roles instead
  7. Separate Concerns: Create focused, single-purpose roles
  8. Monitor Changes: Enable admin action logging

Next Steps


Additional Resources