Adding and Removing Magento Users | OpsBlu Docs

Adding and Removing Magento Users

Complete guide to managing the full user lifecycle in Magento 2, from account creation to secure offboarding and access audits.

Proper user lifecycle management ensures secure access control and compliance in Magento 2. This guide covers creating admin users, managing account settings, implementing secure offboarding procedures, and maintaining access audits.


Adding New Users

Via Admin Panel

Step-by-Step Process

1. Navigate to User Management:

System > Permissions > All Users > Add New User

2. Account Information Tab:

Required Fields:

  • User Name: Unique identifier (lowercase, no spaces)
    • Example: john.smith or jsmith
  • First Name: User's first name
  • Last Name: User's last name
  • Email: Valid email address for notifications
  • Password: Strong password meeting policy requirements
  • Password Confirmation: Must match password

Optional Fields:

  • Interface Locale: Language preference (English, French, etc.)
  • This account is: Active/Inactive status

3. User Role Tab:

Assign Role:

  • Select appropriate role from dropdown
  • Only one role per user
  • Create custom role if needed

4. Current User Identity Verification:

Security Check:

  • Your Password: Enter your current admin password
  • Required for audit trail

5. Save User:

  • Click "Save User" button
  • User appears in grid
  • Confirmation message displayed

Admin Panel Example

Creating Marketing User:

User Name: jane.marketing
First Name: Jane
Last Name: Doe
Email: jane.doe@company.com
Password: [Generate strong password]
Interface Locale: English (United States)
Status: Active
User Role: Marketing Manager
Your Password: [Your admin password]

Via Command Line (CLI)

Create Admin User

Basic Command:

php bin/magento admin:user:create \
    --admin-user="username" \
    --admin-password="StrongPass123!" \
    --admin-email="user@example.com" \
    --admin-firstname="First" \
    --admin-lastname="Last"

With Role Assignment:

php bin/magento admin:user:create \
    --admin-user="catalog.manager" \
    --admin-password="SecurePass456!" \
    --admin-email="catalog@company.com" \
    --admin-firstname="Catalog" \
    --admin-lastname="Manager" \
    --admin-role="Catalog Manager"

Interactive Mode:

# Run command without parameters for prompts
php bin/magento admin:user:create

# System will prompt for each field:
Admin user: catalog.editor
Admin password: ********
Admin email: editor@company.com
Admin first name: Catalog
Admin last name: Editor

Verify Creation

List all admin users:

php bin/magento admin:user:list

Output:

+----+------------------+-----------+----------+----------------------+
| ID | Username         | First     | Last     | Email                |
+----+------------------+-----------+----------+----------------------+
| 1  | admin            | Admin     | User     | admin@company.com    |
| 2  | catalog.manager  | Catalog   | Manager  | catalog@company.com  |
| 3  | jane.marketing   | Jane      | Doe      | jane@company.com     |
+----+------------------+-----------+----------+----------------------+

Programmatic User Creation

Custom Module Implementation

File: app/code/Vendor/Module/Model/UserCreator.php

<?php
namespace Vendor\Module\Model;

use Magento\User\Model\UserFactory;
use Magento\Authorization\Model\RoleFactory;
use Magento\Framework\Exception\LocalizedException;
use Psr\Log\LoggerInterface;

class UserCreator
{
    protected $userFactory;
    protected $roleFactory;
    protected $logger;

    public function __construct(
        UserFactory $userFactory,
        RoleFactory $roleFactory,
        LoggerInterface $logger
    ) {
        $this->userFactory = $userFactory;
        $this->roleFactory = $roleFactory;
        $this->logger = $logger;
    }

    /**
     * Create admin user with role
     *
     * @param array $userData
     * @param string $roleName
     * @return \Magento\User\Model\User
     * @throws LocalizedException
     */
    public function createUser($userData, $roleName)
    {
        try {
            // Validate required fields
            $this->validateUserData($userData);

            // Create user
            $user = $this->userFactory->create();
            $user->setData([
                'username' => $userData['username'],
                'firstname' => $userData['firstname'],
                'lastname' => $userData['lastname'],
                'email' => $userData['email'],
                'password' => $userData['password'],
                'is_active' => $userData['is_active'] ?? 1,
                'interface_locale' => $userData['locale'] ?? 'en_US'
            ]);

            $user->save();

            // Assign role
            $role = $this->getRoleByName($roleName);
            if ($role) {
                $user->setRoleId($role->getId());
                $user->save();
            }

            $this->logger->info('Admin user created: ' . $userData['username']);

            return $user;

        } catch (\Exception $e) {
            $this->logger->error('User creation failed: ' . $e->getMessage());
            throw new LocalizedException(__('Unable to create user: %1', $e->getMessage()));
        }
    }

    protected function validateUserData($data)
    {
        $required = ['username', 'firstname', 'lastname', 'email', 'password'];

        foreach ($required as $field) {
            if (empty($data[$field])) {
                throw new LocalizedException(__('Missing required field: %1', $field));
            }
        }

        // Validate email
        if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
            throw new LocalizedException(__('Invalid email address'));
        }

        // Check username uniqueness
        $existingUser = $this->userFactory->create()->loadByUsername($data['username']);
        if ($existingUser->getId()) {
            throw new LocalizedException(__('Username already exists'));
        }
    }

    protected function getRoleByName($roleName)
    {
        $role = $this->roleFactory->create();
        $role->load($roleName, 'role_name');

        return $role->getId() ? $role : null;
    }
}

Usage:

$userCreator = $objectManager->get(\Vendor\Module\Model\UserCreator::class);

$userData = [
    'username' => 'new.user',
    'firstname' => 'New',
    'lastname' => 'User',
    'email' => 'newuser@company.com',
    'password' => 'SecurePassword123!',
    'is_active' => 1,
    'locale' => 'en_US'
];

$user = $userCreator->createUser($userData, 'Marketing Manager');

Bulk User Import

CSV Import Script

CSV Format: users.csv

username,firstname,lastname,email,password,role,active
john.smith,John,Smith,john@company.com,Pass123!,Marketing Manager,1
jane.doe,Jane,Doe,jane@company.com,Pass456!,Content Editor,1
bob.johnson,Bob,Johnson,bob@company.com,Pass789!,Catalog Manager,1

Import Script:

<?php
use Magento\Framework\App\Bootstrap;

require __DIR__ . '/app/bootstrap.php';

$bootstrap = Bootstrap::create(BP, $_SERVER);
$objectManager = $bootstrap->getObjectManager();
$state = $objectManager->get(\Magento\Framework\App\State::class);
$state->setAreaCode(\Magento\Framework\App\Area::AREA_ADMINHTML);

$userCreator = $objectManager->get(\Vendor\Module\Model\UserCreator::class);

$csvFile = 'users.csv';
$handle = fopen($csvFile, 'r');

// Skip header row
$header = fgetcsv($handle);

while (($row = fgetcsv($handle)) !== false) {
    $userData = [
        'username' => $row[0],
        'firstname' => $row[1],
        'lastname' => $row[2],
        'email' => $row[3],
        'password' => $row[4],
        'is_active' => (int)$row[6]
    ];

    $roleName = $row[5];

    try {
        $user = $userCreator->createUser($userData, $roleName);
        echo "Created user: {$userData['username']}\n";
    } catch (\Exception $e) {
        echo "Error creating {$userData['username']}: {$e->getMessage()}\n";
    }
}

fclose($handle);

Run Import:

php import_users.php

Managing Existing Users

Updating User Information

Via Admin Panel:

System > Permissions > All Users > [Select User] > Edit

Update Fields:

  • First/Last Name
  • Email
  • Password (optional)
  • Interface Locale
  • Account Status (Active/Inactive)
  • Role Assignment

Via CLI:

# Unlock user account
php bin/magento admin:user:unlock username

# Reset password
php bin/magento admin:user:reset-password username

Programmatically:

$user = $userFactory->create()->loadByUsername('john.smith');
$user->setFirstname('John');
$user->setLastname('Smith-Johnson');
$user->setEmail('john.new@company.com');
$user->save();

Password Reset

Force Password Reset:

Admin Panel:

  1. Edit user
  2. Check "Send Password Reset Email"
  3. Save user
  4. User receives email with reset link

CLI:

php bin/magento admin:user:reset-password john.smith

Programmatic:

$user = $userFactory->create()->loadByUsername('john.smith');
$user->sendPasswordResetNotificationEmail();

Activating/Deactivating Users

Temporary Deactivation:

Admin Panel:

  1. Edit user
  2. Set "This account is" to "Inactive"
  3. Save user

CLI (Custom Command):

# Create custom command for deactivation
php bin/magento user:deactivate john.smith

Programmatic:

$user = $userFactory->create()->loadByUsername('john.smith');
$user->setIsActive(0);  // 0 = Inactive, 1 = Active
$user->save();

Removing Users

Secure Offboarding Process

Step 1: Disable Account

Immediately suspend access:

System > Permissions > All Users > [Select User] > Edit
Set "This account is" to "Inactive"
Save User

Or via CLI:

# Disable user
php bin/magento admin:user:deactivate username

Step 2: Transfer Ownership

Before deletion, transfer:

  • Content ownership (CMS pages, blocks)
  • Scheduled tasks
  • Custom reports
  • Integration tokens
  • API credentials

Database Query to Find Owned Content:

-- Find CMS pages created by user
SELECT page_id, title, creation_time
FROM cms_page
WHERE author_id = (SELECT user_id FROM admin_user WHERE username = 'john.smith');

-- Find scheduled operations
SELECT schedule_id, job_code, created_at
FROM cron_schedule
WHERE user_id = (SELECT user_id FROM admin_user WHERE username = 'john.smith');

Reassign Content:

// Reassign CMS pages
$newOwner = $userFactory->create()->loadByUsername('new.owner');
$oldOwner = $userFactory->create()->loadByUsername('john.smith');

$pageCollection = $pageCollectionFactory->create();
$pageCollection->addFieldToFilter('author_id', $oldOwner->getId());

foreach ($pageCollection as $page) {
    $page->setAuthorId($newOwner->getId());
    $page->save();
}

Step 3: Revoke API Access

Remove integrations:

System > Extensions > Integrations
  • Find integrations owned by user
  • Delete or reassign

Revoke OAuth tokens:

-- Revoke user's OAuth tokens
DELETE FROM oauth_token
WHERE admin_id = (SELECT user_id FROM admin_user WHERE username = 'john.smith');

-- Revoke integration tokens
DELETE FROM integration
WHERE email = 'john.smith@company.com';

Step 4: Export Audit Trail

Before deletion, export:

System > Action Logs > Report
  • Filter by user
  • Export to CSV
  • Save for compliance

SQL Export:

-- Export user's action log
SELECT *
FROM logging_event
WHERE user_id = (SELECT user_id FROM admin_user WHERE username = 'john.smith')
ORDER BY time DESC
INTO OUTFILE '/tmp/user_audit_john_smith.csv';

Step 5: Delete User Account

Via Admin Panel:

System > Permissions > All Users > [Select User] > Delete

Via Database (Not Recommended):

-- Only use if admin panel is unavailable
DELETE FROM admin_user WHERE username = 'john.smith';
DELETE FROM authorization_role WHERE user_id = [user_id];

Via CLI (Custom Command):

php bin/magento admin:user:delete john.smith

Step 6: Document Offboarding

Create offboarding ticket:

  • User Name
  • Termination Date
  • Reason for Removal
  • Content Reassigned
  • API Tokens Revoked
  • Audit Trail Exported
  • Approver Name

Bulk User Management

Deactivate Multiple Users

SQL Script:

-- Deactivate all users except admin
UPDATE admin_user
SET is_active = 0
WHERE username != 'admin'
AND user_id > 1;

Programmatic:

$userCollection = $userCollectionFactory->create();
$userCollection->addFieldToFilter('username', ['neq' => 'admin']);

foreach ($userCollection as $user) {
    $user->setIsActive(0);
    $user->save();
    echo "Deactivated: " . $user->getUsername() . "\n";
}

Delete Inactive Users

Find inactive users (30+ days):

SELECT username, email, logdate, is_active
FROM admin_user
WHERE is_active = 0
AND logdate < DATE_SUB(NOW(), INTERVAL 30 DAY);

Delete after verification:

$userCollection = $userCollectionFactory->create();
$userCollection->addFieldToFilter('is_active', 0);
$userCollection->addFieldToFilter(
    'logdate',
    ['lt' => date('Y-m-d H:i:s', strtotime('-30 days'))]
);

foreach ($userCollection as $user) {
    echo "Deleting: " . $user->getUsername() . "\n";
    $user->delete();
}

Access Audits

Regular Access Reviews

Quarterly Review Process:

  1. Generate User Report:

    php bin/magento admin:user:list > users_$(date +%Y%m%d).txt
    
  2. Check Last Login:

    SELECT username, email, logdate, lognum
    FROM admin_user
    ORDER BY logdate DESC;
    
  3. Identify Stale Accounts:

    -- Users who haven't logged in for 90 days
    SELECT username, email, logdate
    FROM admin_user
    WHERE logdate < DATE_SUB(NOW(), INTERVAL 90 DAY)
    AND is_active = 1
    ORDER BY logdate ASC;
    
  4. Review Roles:

    SELECT u.username, u.email, r.role_name
    FROM admin_user u
    LEFT JOIN authorization_role r ON u.user_id = r.user_id
    WHERE u.is_active = 1
    ORDER BY r.role_name, u.username;
    
  5. Document Review:

    • Export results
    • Manager approval for each active user
    • Remove unnecessary access
    • Update documentation

Compliance Reporting

Generate compliance report:

<?php
class AccessAuditReport
{
    public function generateReport()
    {
        $report = [
            'generated_at' => date('Y-m-d H:i:s'),
            'total_users' => 0,
            'active_users' => 0,
            'inactive_users' => 0,
            'roles' => [],
            'users_by_role' => []
        ];

        $userCollection = $this->userCollectionFactory->create();
        $report['total_users'] = $userCollection->getSize();

        $activeUsers = clone $userCollection;
        $activeUsers->addFieldToFilter('is_active', 1);
        $report['active_users'] = $activeUsers->getSize();

        $inactiveUsers = clone $userCollection;
        $inactiveUsers->addFieldToFilter('is_active', 0);
        $report['inactive_users'] = $inactiveUsers->getSize();

        // Group by role
        foreach ($activeUsers as $user) {
            $role = $user->getRole();
            $roleName = $role ? $role->getRoleName() : 'No Role';

            if (!isset($report['users_by_role'][$roleName])) {
                $report['users_by_role'][$roleName] = [];
            }

            $report['users_by_role'][$roleName][] = [
                'username' => $user->getUsername(),
                'email' => $user->getEmail(),
                'last_login' => $user->getLogdate()
            ];
        }

        return $report;
    }
}

Security Best Practices

Password Requirements

Enforce strong passwords:

Stores > Configuration > Advanced > Admin > Security
  • Minimum Length: 12+ characters
  • Required Characters: Numbers, symbols, upper/lower case
  • Password Lifetime: 90 days
  • Lock after failures: 5 attempts

Two-Factor Authentication (2FA)

Mandatory 2FA for new users:

# Enable 2FA for user
php bin/magento security:tfa:google:set-secret john.smith [SECRET_KEY]

Session Management

Configure sessions:

Stores > Configuration > Advanced > Admin > Security
  • Session Lifetime: 900 seconds (15 min)
  • Validate HTTP_USER_AGENT: Yes
  • Validate REMOTE_ADDR: Yes

Access Logging

Enable action logs:

Stores > Configuration > Advanced > Admin > Admin Actions Log Archiving
  • Enable Archiving: Yes
  • Log Lifetime: 365 days

Troubleshooting

Cannot Create User

Error: "User name already exists"

Solution:

-- Check for existing username
SELECT * FROM admin_user WHERE username = 'desired_username';

-- If exists, choose different username or delete old account

User Cannot Login

Possible Causes:

  1. Account Inactive:

    UPDATE admin_user SET is_active = 1 WHERE username = 'john.smith';
    
  2. Account Locked:

    php bin/magento admin:user:unlock john.smith
    
  3. Wrong Password:

    php bin/magento admin:user:reset-password john.smith
    

Permissions Not Working After Creation

Solution:

# Clear ACL cache
php bin/magento cache:clean config
php bin/magento cache:flush

Automation Examples

Automated User Provisioning

SSO Integration (Example with SAML):

public function createUserFromSaml($samlData)
{
    $username = $samlData['username'];
    $email = $samlData['email'];

    // Check if user exists
    $user = $this->userFactory->create()->loadByUsername($username);

    if (!$user->getId()) {
        // Create new user
        $user = $this->userCreator->createUser([
            'username' => $username,
            'firstname' => $samlData['firstname'],
            'lastname' => $samlData['lastname'],
            'email' => $email,
            'password' => bin2hex(random_bytes(16)),  // Random password
            'is_active' => 1
        ], $samlData['role']);
    }

    return $user;
}

Scheduled User Cleanup

Cron Job: Remove inactive users after 90 days

<!-- etc/crontab.xml -->
<config>
    <group id="default">
        <job name="cleanup_inactive_users" instance="Vendor\Module\Cron\CleanupUsers" method="execute">
            <schedule>0 2 * * 0</schedule>  <!-- Weekly on Sunday at 2 AM -->
        </job>
    </group>
</config>
<?php
namespace Vendor\Module\Cron;

class CleanupUsers
{
    public function execute()
    {
        $collection = $this->userCollectionFactory->create();
        $collection->addFieldToFilter('is_active', 0);
        $collection->addFieldToFilter(
            'logdate',
            ['lt' => date('Y-m-d H:i:s', strtotime('-90 days'))]
        );

        foreach ($collection as $user) {
            $this->logger->info('Auto-deleting inactive user: ' . $user->getUsername());
            $user->delete();
        }
    }
}

Next Steps


Additional Resources