set up, enforce and extend with a custom provider
A compromised admin password is one of the most common entry points for attackers against Magento stores, because a single factor is enough to take over payment configuration, customer data and the entire store setup. This article shows how to configure the Magento_TwoFactorAuth module, which providers are available, how to enforce Two-Factor Authentication store-wide through configuration or per role, how the underlying CLI commands work, how to implement a custom TFA provider using the ProviderInterface, how to register it through di.xml, and which pitfalls typically appear when operating 2FA behind a reverse proxy, in a headless setup or on a staging environment.
Table of Contents
- 1. Why Two-Factor Authentication is mandatory in the admin panel
- 2. Configuring Magento_TwoFactorAuth through system.xml
- 3. Provider overview: TOTP, Duo, U2F/WebAuthn, Authy
- 4. Enforcing 2FA: globally vs. per role
- 5. The security:tfa CLI commands in detail
- 6. Implementing a custom TFA provider with ProviderInterface
- 7. Registering the provider pool in di.xml
- 8. 2FA in a headless context: REST, GraphQL and recovery codes
- 9. Common operational pitfalls
- 10. Summary
- 11. FAQ
1. Why Two-Factor Authentication is mandatory in the admin panel
The Magento admin panel is the central attack surface of any store: from here, an attacker can configure payment methods, create admin users, and even inject executable code through custom modules and layout XML. A single password as the only protection factor is no longer an adequate security level given credential stuffing, phishing campaigns and password reuse from unrelated data breaches. This is exactly where Two-Factor Authentication comes in: even if an attacker knows the admin password, the second factor, whether a TOTP code, a hardware token or a push notification, prevents the unauthorized login from succeeding.
Since Magento 2.3.7, the Magento_TwoFactorAuth module has shipped in both editions, Open Source and Adobe Commerce. Since Magento 2.4.x, Two-Factor Authentication is enabled by default in Adobe Commerce and can no longer be turned off without consequences, while it remains optional but strongly recommended in Magento Open Source. In version 2.4.8-p4, which this article uses as its reference, the provider architecture is fully built on service contracts, which makes custom extensions considerably cleaner than in the early 2.3.x releases. Anyone who still treats Two-Factor Authentication as an optional feature today is ignoring one of the most effective and, at the same time, easiest to implement security measures for the admin panel.
An important clarification: Two-Factor Authentication only protects the interactive admin login through the backend UI. It does not replace other security measures such as IP whitelisting, role and permission management through ACL, or regular password rotation, but adds an additional layer of defense on top of them. Combined with a restrictive role setup and a well-maintained ACL structure, Two-Factor Authentication forms the foundation of resilient admin security.
2. Configuring Magento_TwoFactorAuth through system.xml
Magento_TwoFactorAuth is configured through Stores > Configuration > Security > 2FA, defined in the module through a dedicated system.xml section identified as twofactorauth. This section is deliberately disabled at website or store view scope and only applies at default scope, because Two-Factor Authentication is a property of the admin area and must not vary per storefront view. Within the section, each provider exposes its own activation toggle plus provider-specific fields such as the API key for Duo Security or the application ID for U2F.
The central setting force_providers determines which providers are enforced for every admin user. Entering google for Google Authenticator means every admin user must enroll with TOTP on their next login before backend access is granted. Multiple providers can be combined with a comma, letting users choose from a set, for example TOTP or U2F/WebAuthn in parallel. The configuration can be fully exported and version-controlled through app/etc/config.php, which should be mandatory in deployment pipelines so the 2FA configuration does not accidentally drift between environments.
<!-- app/code/Mironsoft/Security/etc/adminhtml/system.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
<system>
<section id="twofactorauth" translate="label" type="text"
sortOrder="20" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Two-Factor Authentication</label>
<tab>security</tab>
<resource>Magento_TwoFactorAuth::config</resource>
<group id="general" translate="label" type="text"
sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
<label>General</label>
<field id="force_providers" translate="label comment" type="multiselect"
sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Force Providers</label>
<comment>Enforced providers apply to every admin user without exception.</comment>
<source_model>Magento\TwoFactorAuth\Model\Config\Source\Providers</source_model>
</field>
</group>
<group id="u2f" translate="label" type="text"
sortOrder="30" showInDefault="1" showInWebsite="0" showInStore="0">
<label>U2F / WebAuthn</label>
<field id="relying_party_id" translate="label comment" type="text"
sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
<label>Relying Party ID</label>
<comment>Must exactly match the admin panel domain, otherwise the origin check fails.</comment>
</field>
</group>
</section>
</system>
</config>
In addition to the global configuration, Magento_TwoFactorAuth ships an ACL resource per provider, so Two-Factor Authentication can in principle also be governed based on admin user roles, even though the full per-role enforcement logic is more limited in the community edition than in Adobe Commerce with Magento_AdminAdobeIms. Anyone needing finer control over individual roles combines the default configuration with a custom plugin on AuthenticationInterface that inspects the role of the logging-in user and adjusts the provider requirement dynamically.
3. Provider overview: TOTP, Duo, U2F/WebAuthn, Authy
Magento_TwoFactorAuth ships four built-in provider implementations out of the box, each backed by a class that fulfills the Magento\TwoFactorAuth\Api\ProviderInterface interface. The Google Authenticator provider, referenced internally as google, implements the TOTP standard per RFC 6238 and works with any compatible authenticator app such as Google Authenticator, Microsoft Authenticator or Authy in TOTP mode. The secret key is stored per user in the tfa_user_config table and presented as a QR code on first login.
The Duo Security provider connects to the Duo cloud infrastructure through a dedicated API and is particularly relevant for organizations that already run a Duo setup for other systems. It requires configuring the integration key, secret key and API hostname in the system.xml section, and works through push notifications to a mobile app, which is more convenient for end users than manually typing a TOTP code, but introduces a dependency on an external cloud service. The U2F provider, technically implemented through WebAuthn today, uses physical hardware tokens such as YubiKeys or platform-bound authenticators like Touch ID and Windows Hello. It offers the highest security level, because the private key never leaves the device and phishing is practically ruled out by the origin binding of the WebAuthn protocol. Authy finally acts primarily as a TOTP-compatible app and is supported through the same google provider, as long as the shared secret is imported correctly.
Choosing the right provider depends on how many admin users a store has and how strict the required protection level needs to be. Smaller teams usually do best with TOTP through Google Authenticator, while larger organizations with stricter compliance requirements benefit from U2F/WebAuthn or Duo Security. Two-Factor Authentication should never be introduced in isolation for individual users, but consistently for every admin role with write access, so no unprotected backdoor remains.
4. Enforcing 2FA: globally vs. per role
The simplest form of enforcement is the global configuration through force_providers, which applies to every admin user without exception. This is the recommended setting for production stores, because a single unprotected account would undermine the entire security concept. In practice, it is still often desirable to introduce enforcement in stages: first as an optional offer to administrators, then mandatory for everyone after a transition period.
For role-based differentiation, for instance stricter requirements for super administrators than for support staff with limited ACL rights, the default configuration of Magento_TwoFactorAuth alone is not sufficient. A plugin on Magento\TwoFactorAuth\Model\Provider\Engine\Google or directly on AuthenticationInterface is a good fit here, checking the assigned role of the user and enforcing different provider requirements depending on the role ID. It is important that such a plugin never fully bypasses the 2FA check, but only differentiates between different enforced providers, so no bypass path for Two-Factor Authentication is introduced.
A frequently overlooked aspect: enforcement of Two-Factor Authentication applies per admin website configuration value, not per individual user account. If a new provider is added to the force_providers list, every existing admin user must re-enroll on their next login unless they already configured that particular provider. This can lead to unexpected support requests after a configuration change, since users suddenly encounter a QR code they did not expect.
5. The security:tfa CLI commands in detail
Magento_TwoFactorAuth ships its own set of CLI commands under the security:tfa namespace, which are indispensable for administrative emergencies and automation. The command bin/magento security:tfa:google:remove-secret removes the TOTP secret of a specific admin user and is the standard way to restore access for a locked-out administrator without disabling the entire 2FA configuration. The call expects the username as a parameter and resets the enrollment status for that provider, so a new QR code is displayed on the next login.
The command bin/magento security:tfa:u2f:remove-registrations deletes all registered U2F/WebAuthn tokens for a user, which becomes necessary in particular when a hardware token is lost or an employee has left the company. It is worth adding these commands to a documented support runbook, because they need to be executed correctly under time pressure in an emergency. Without CLI access to the production server, a locked-out administrator would otherwise only have the option of a direct database change, which is more error-prone and harder to trace.
# List all available TFA providers with their current status
bin/magento security:tfa:google:remove-secret admin_username
# Remove all U2F / WebAuthn registrations for a locked-out user
bin/magento security:tfa:u2f:remove-registrations admin_username
# Force a full reset of all providers for a single admin user
# (run both commands together for a clean re-enrollment)
bin/magento security:tfa:google:remove-secret support_user
bin/magento security:tfa:u2f:remove-registrations support_user
# Inspect module status before disabling in a staging environment
bin/magento module:status Magento_TwoFactorAuth
# Disable the module temporarily on staging only, never on production
bin/magento module:disable Magento_TwoFactorAuth
Another important command around provider management is bin/magento module:disable Magento_TwoFactorAuth, which must be used with extreme caution. It disables Two-Factor Authentication entirely for every admin user and should only ever be used on isolated development or test environments, never on a production or production-like staging system with real customer data. Section nine covers this point in more detail as one of the most common operational traps.
6. Implementing a custom TFA provider with ProviderInterface
For organizations with an existing identity provider infrastructure, such as an internal SSO system or a specialized hardware security module, implementing a custom provider for Two-Factor Authentication is worthwhile. The foundation is the Magento\TwoFactorAuth\Api\ProviderInterface interface, which requires methods such as getCode(), isActive(), isApplicableToUser() and getConfiguration(). A custom provider often also needs to implement Magento\TwoFactorAuth\Api\ProviderInfoInterface, which supplies metadata such as the provider's name and description for the UI selection.
The following example implementation shows a minimal but fully functional provider that validates codes through an internal enterprise SSO service. It uses constructor property promotion following PHP 8.4 conventions and keeps external dependencies cleanly separated through service contracts.
<?php
declare(strict_types=1);
namespace Mironsoft\Security\Model\Provider;
use Magento\TwoFactorAuth\Api\ProviderInfoInterface;
use Magento\TwoFactorAuth\Api\ProviderInterface;
use Magento\TwoFactorAuth\Api\Data\ProviderInfoInterfaceFactory;
use Magento\User\Api\Data\UserInterface;
use Mironsoft\Security\Api\EnterpriseSsoClientInterface;
/**
* Custom TFA provider that validates codes against an internal
* enterprise SSO service instead of a local TOTP secret.
*/
class EnterpriseSsoProvider implements ProviderInterface, ProviderInfoInterface
{
public const CODE = 'enterprise_sso';
/**
* @param EnterpriseSsoClientInterface $ssoClient Client that talks to the internal SSO service.
* @param ProviderInfoInterfaceFactory $providerInfoFactory Factory for provider metadata objects.
* @param bool $enabled Whether this provider is active, taken from system.xml configuration.
*/
public function __construct(
private readonly EnterpriseSsoClientInterface $ssoClient,
private readonly ProviderInfoInterfaceFactory $providerInfoFactory,
private readonly bool $enabled = true,
) {
}
/**
* Returns the unique provider code used in the provider pool.
*
* @return string
*/
public function getCode(): string
{
return self::CODE;
}
/**
* Determines whether this provider is currently active.
*
* @return bool
*/
public function isActive(): bool
{
return $this->enabled;
}
/**
* Determines whether this provider applies to the given admin user,
* e.g. based on a custom user attribute set by the SSO sync job.
*
* @param UserInterface $user Admin user being evaluated.
* @return bool
*/
public function isApplicableToUser(UserInterface $user): bool
{
return (bool) $user->getExtensionAttributes()?->getSsoManaged();
}
/**
* Validates the one-time code entered by the user against the
* enterprise SSO backend.
*
* @param UserInterface $user Admin user attempting to log in.
* @param string $code Code entered in the admin login form.
* @return bool
* @throws \Magento\Framework\Exception\AuthenticationException
*/
public function verify(UserInterface $user, string $code): bool
{
return $this->ssoClient->validateCode((int) $user->getId(), $code);
}
/**
* Returns provider metadata for the TFA provider selection UI.
*
* @return ProviderInfoInterface
*/
public function getConfiguration(): ProviderInfoInterface
{
return $this->providerInfoFactory->create([
'data' => [
'code' => self::CODE,
'name' => 'Enterprise SSO',
'configureAction' => 'mironsoft_security/sso/configure',
],
]);
}
}
The decisive difference from the built-in providers lies in isApplicableToUser(): a custom provider for Two-Factor Authentication can become active only for specific user groups, for example employees managed through the central SSO service, while local admin accounts keep using TOTP. This flexibility makes ProviderInterface a powerful extension point that goes well beyond the four standard providers of Magento_TwoFactorAuth.
7. Registering the provider pool in di.xml
For Magento to recognize the new provider, it must be hooked into the central provider pool. Magento_TwoFactorAuth manages all registered providers through a virtualType named Magento\TwoFactorAuth\Model\Provider\Pool, configured as an array list, to which the di.xml adds an additional entry. The sortOrder determines in which order providers are presented to the user in the selection, which matters in particular when several providers are enforced simultaneously.
<!-- app/code/Mironsoft/Security/etc/di.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<!-- Register the custom provider as a plain service class -->
<preference for="Mironsoft\Security\Api\EnterpriseSsoClientInterface"
type="Mironsoft\Security\Model\EnterpriseSsoClient"/>
<type name="Mironsoft\Security\Model\Provider\EnterpriseSsoProvider">
<arguments>
<argument name="enabled" xsi:type="boolean">true</argument>
</arguments>
</type>
<!-- Hook into the existing TFA provider pool -->
<virtualType name="Magento\TwoFactorAuth\Model\Provider\Pool">
<arguments>
<argument name="providers" xsi:type="array">
<item name="enterprise_sso" xsi:type="array">
<item name="instance" xsi:type="string">
Mironsoft\Security\Model\Provider\EnterpriseSsoProvider
</item>
<item name="sortOrder" xsi:type="number">50</item>
</item>
</argument>
</arguments>
</virtualType>
</config>
After deploying this di.xml change, the new provider automatically appears in the list of selectable providers under the force_providers system.xml configuration, without any change to the core logic of Magento_TwoFactorAuth. That is the central advantage of the pool pattern: extensions for Two-Factor Authentication happen additively through dependency injection, not through preferences on core classes, which makes upgrades to later Magento versions considerably easier. After every di.xml change, a bin/magento cache:flush and, on production setups, a setup:di:compile are required so the object manager picks up the new configuration.
8. 2FA in a headless context: REST, GraphQL and recovery codes
A common misconception concerns the scope of Two-Factor Authentication in headless architectures, where a PWA Studio frontend or a custom storefront communicates with Magento exclusively through REST or GraphQL APIs. Two-Factor Authentication is strictly a UI-layer feature of the admin panel and only applies during interactive login through the backend interface. Token-based authentication for customers through REST (customerToken) or GraphQL (generateCustomerToken) is entirely unaffected by Two-Factor Authentication, because these are two completely independent security layers: one protects customer accounts in the storefront, the other protects administrative access in the backend.
For integrations that generate admin tokens programmatically, for instance integrationToken for third-party system integrations, Two-Factor Authentication also does not apply, because this authentication path runs technically separate from the interactive admin session and is instead secured through OAuth credentials. In practice, this means an attacker trying to log in through the admin UI is stopped by Two-Factor Authentication, while an API client with valid integration credentials keeps working independently of it. Anyone wanting to secure API access must therefore rely on separate mechanisms such as IP whitelisting for REST endpoints, short token lifetimes and clean scope management of integration permissions, not on Two-Factor Authentication.
For the case where an admin user loses their second factor, for instance a broken smartphone with the authenticator app or a misplaced hardware token, Magento_TwoFactorAuth does not ship an integrated backup code system like many SaaS applications do. Instead, an administrator with access to the security:tfa CLI commands acts as the recovery instance and resets the affected provider for the user. Larger organizations frequently complement this with their own recovery code mechanism as an additional custom provider, generating one-time codes at initial setup and storing them encrypted in the database, so a user can regain access on their own in an emergency without administrative intervention.
| Provider | Setup Effort | Security Level | Recommendation |
|---|---|---|---|
| Google Authenticator (TOTP) | Low, no additional infrastructure | Solid, vulnerable to code phishing | Default for small to mid-sized teams |
| Duo Security | Medium, requires Duo account and API keys | High, push confirmation with device context | Good fit with existing Duo infrastructure |
| U2F / WebAuthn | Higher, needs hardware token or platform auth | Very high, origin-bound, phishing-resistant | Recommended for super administrators |
| Authy (via TOTP) | Low, compatible with the Google provider | Solid, same as standard TOTP | Alternative app for existing Authy users |
| Custom provider (e.g. SSO) | High, custom ProviderInterface implementation | Depends on the implementation | Sensible with existing identity infrastructure |
9. Common operational pitfalls
The most common operational trap with Two-Factor Authentication happens during development: a developer disables Magento_TwoFactorAuth on a staging environment to test faster without entering a TOTP code on every login, and then forgets to re-enable the module before deploying to production. Since Magento module status is version-controlled through app/etc/config.php, such a state can silently reach production if the configuration file is taken over without review. A reliable safeguard against this is an automated check in the deployment pipeline that verifies, before every production deployment, that Magento_TwoFactorAuth is recorded as enabled in the module status, and blocks the deployment on any discrepancy.
A second common trap concerns accidentally locking yourself out of your own admin access when first testing Two-Factor Authentication on a new environment. If force_providers is set before your own TOTP code has been correctly set up and tested, access to the admin panel can be blocked entirely. In this case, direct database access or the CLI commands from section five are the only way out, which is why it is advisable to keep a second, independently authenticated admin account available before changing the 2FA configuration.
A third, more technically subtle trap concerns operating behind a reverse proxy or load balancer when using U2F/WebAuthn. The WebAuthn protocol cryptographically binds every signature to the origin, meaning the protocol, hostname and optionally the port under which the admin panel is accessed. If relying_party_id in the system.xml configuration is not set to exactly match the publicly visible domain, or if a reverse proxy terminates TLS and forwards requests over HTTP to the Magento container without passing through the correct X-Forwarded-Proto header, the WebAuthn origin check fails and users can no longer log in with their hardware token. The fix is to configure the reverse proxy so it correctly sets X-Forwarded-Proto and X-Forwarded-Host, and to enter the trusted proxy IP addresses in Magento through the trusted_proxies parameter in app/etc/env.php, so Magento determines the actual origin correctly instead of the internal proxy address.
10. Summary
Two-factor authentication in the Magento 2 admin panel is built on the core module Magento_TwoFactorAuth, which supports several providers, from simple TOTP through U2F/WebAuthn to self-implemented providers for existing SSO infrastructure. The force_providers configuration can make 2FA mandatory for all administrators, while CLI commands such as security:tfa:reset and security:tfa:show-providers enable emergency access and a provider overview if an administrator gets locked out.
The three biggest operational risks are a module accidentally disabled on the way from staging to production, force_providers being set too early before the first successful test, and a misconfigured reverse proxy that breaks WebAuthn's origin check. Anyone who knows these three traps and keeps a second, independently authenticated emergency account available can roll out 2FA in production without any lockout risk.
Two-factor authentication in the admin panel, the essentials at a glance
Core module
Magento_TwoFactorAuth supports TOTP, U2F/WebAuthn, Authy and custom providers via ProviderInterface.
Enforcement
force_providers makes 2FA mandatory for all admin users, but should only be set after a successful test.
Emergency access
security:tfa:reset and direct database access prevent a permanent lockout.
Reverse proxy
Set relying_party_id and trusted_proxies correctly, otherwise the WebAuthn origin check fails.
11. FAQ: Two-Factor Authentication in the Magento Admin Panel
1Which module controls 2FA in Magento 2?
2How do I enforce 2FA for all admins?
3TOTP or U2F/WebAuthn?
4Locked out, what now?
5Custom provider for SSO possible?
6Why does a disabled module reach production?
7Why does WebAuthn fail behind a reverse proxy?
8How do I configure trusted_proxies correctly?
9Which provider for super administrators?
10Most important precaution beforehand?
Mironsoft
Magento Security, admin hardening and Two-Factor Authentication
Ready to anchor Two-Factor Authentication properly in your admin panel?
We set up Magento_TwoFactorAuth for production, choose the right provider for your team and, if needed, implement a custom provider for existing SSO or identity infrastructure, with a clean rollout and no lockout risk.
Security Audit
Review of existing admin security including 2FA configuration, ACL roles and access paths
2FA Rollout
Provider selection, staged rollout and custom provider development for existing identity systems
Incident Response
Emergency runbooks for locked-out admin users and fast restoration of access