By default, Magento 2 redirects customers to their Account Dashboard immediately after a successful login. While this is standard for most e-commerce stores, many business requirements demand a different user flow. You might want to send users back to a promotional landing page, their order history, or a specialized customer portal.

While Magento 2 offers a configuration setting under Stores > Configuration > Customers > Customer Configuration > Login Options, it is often limited. It generally only allows you to choose between the Dashboard or the page the user was on previously. If you need to redirect to a specific custom URL, you will need to implement a programmatic solution.

In this guide, we will explore two primary methods to achieve a custom redirect: using a Plugin (the recommended approach) and using a Preference (an override approach).

Using a plugin is the best practice in Magento 2. Unlike preferences, plugins allow you to extend functionality without completely replacing the core class. This ensures better compatibility with other modules and makes your store easier to upgrade.

To redirect a user after login, we will target the execute method of the Magento\Customer\Controller\Account\LoginPost class.

Step 1: Create di.xml

First, define the plugin in your module's etc/frontend/di.xml file. We use the frontend scope because login actions typically occur on the storefront.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Customer\Controller\Account\LoginPost">
        <plugin name="vendor_module_login_redirect" type="Vendor\Module\Plugin\LoginPostPlugin" sortOrder="1" />
    </type>
</config>

Step 2: Create the Plugin Class

Now, create the PHP class. We will use an afterExecute method to intercept the result of the login process and modify the redirect path.

<?php

namespace Vendor\Module\Plugin;

use Magento\Framework\Controller\Result\Redirect;

class LoginPostPlugin
{
    /**
     * Redirect after login to a custom page instead of the dashboard.
     *
     * @param \Magento\Customer\Controller\Account\LoginPost $subject
     * @param Redirect $result
     * @return Redirect
     */
    public function afterExecute(
        \Magento\Customer\Controller\Account\LoginPost $subject, 
        $result
    ) {
        // Example: Redirect to the Order History page
        $customUrl = 'sales/order/history'; 

        // To redirect to the homepage, use '/'
        // $customUrl = '/';

        $result->setPath($customUrl);
        return $result;
    }
}

Method 2: Using a Preference (Override)

While a plugin is usually sufficient, sometimes you need full control over the login logic, including how exceptions are handled or how the session is managed. In such cases, you can use a preference to override the core controller.

Warning: Use this method sparingly, as it can cause conflicts with other extensions that also attempt to modify the login controller.

Step 1: Create di.xml

Define the preference in your module's etc/di.xml file:

<preference for="Magento\Customer\Controller\Account\LoginPost" type="Vendor\Module\Controller\Account\LoginPost" />

Step 2: Create the Controller Class

Your custom class must extend the original core class and override the execute method.

<?php

namespace Vendor\Module\Controller\Account;

use Magento\Framework\Exception\EmailNotConfirmedException;
use Magento\Framework\Exception\AuthenticationException;

class LoginPost extends \Magento\Customer\Controller\Account\LoginPost 
{
    public function execute() 
    {
        // Check if user is already logged in or form key is invalid
        if ($this->session->isLoggedIn() || !$this->formKeyValidator->validate($this->getRequest())) {
            $resultRedirect = $this->resultRedirectFactory->create();
            $resultRedirect->setPath('home');
            return $resultRedirect;
        }

        if ($this->getRequest()->isPost()) {
            $login = $this->getRequest()->getPost('login');
            if (!empty($login['username']) && !empty($login['password'])) {
                try {
                    $customer = $this->customerAccountManagement->authenticate($login['username'], $login['password']);
                    $this->session->setCustomerDataAsLoggedIn($customer);
                    $this->session->regenerateId();
                } catch (EmailNotConfirmedException $e) {
                    $value = $this->customerUrl->getEmailConfirmationUrl($login['username']);
                    $message = __('This account is not confirmed. <a href="%1">Click here</a> to resend confirmation email.', $value);
                    $this->messageManager->addError($message);
                    $this->session->setUsername($login['username']);
                } catch (AuthenticationException $e) {
                    $message = __('Invalid login or password.');
                    $this->messageManager->addError($message);
                    $this->session->setUsername($login['username']);
                } catch (\Exception $e) {
                    $this->messageManager->addError(__('Invalid login or password.'));
                }
            } else {
                $this->messageManager->addError(__('A login and a password are required.'));
            }
        }

        $resultRedirect = $this->resultRedirectFactory->create();
        $resultRedirect->setPath('home'); // Define your custom path here
        return $resultRedirect;
    }
}

Why the Native Configuration Might Fail

Many developers find that setting "Redirect Customer to Account Dashboard after Logging in" to "No" in the admin panel doesn't always work as expected. This is often because: 1. Referer URLs: Magento tries to send the user back to the referer URL stored in the session. If that URL is expired or invalid, it defaults back to the dashboard. 2. Custom Modules: Third-party checkout or social login modules often override this behavior entirely. 3. Cache Issues: Sometimes the redirect logic is cached in the browser or via a CDN, causing inconsistent behavior.

By using the Plugin method described above, you bypass these settings and explicitly force the routing logic to follow your requirements.

Best Practices and Pitfalls

  • Avoid Hardcoding URLs: Instead of hardcoding sales/order/history, consider using the Magento\Framework\UrlInterface to generate URLs dynamically.
  • Scope Matters: Always place your di.xml for plugins in the etc/frontend folder if the change only applies to the storefront. This keeps the admin area and API requests performant.
  • Compatibility: If you are using Magento 2.4.x, ensure your plugin handles the ResultInterface correctly, as return types have become more strictly enforced in recent PHP versions.

Frequently Asked Questions

Can I redirect to an external URL?

Yes. Instead of using $result->setPath('path'), you can use $result->setUrl('https://external-site.com') within your plugin.

Will this affect the 'Forgot Password' flow?

No. This logic specifically targets the LoginPost controller, which is only triggered when a user submits the login form. Resetting a password uses different controllers.

Wrapping Up

Redirecting a customer to a custom page after login is a powerful way to streamline the user journey. While preferences offer a heavy-duty way to override logic, Plugins remain the most elegant and upgrade-safe solution for Magento 2 developers. By implementing a simple afterExecute plugin on the LoginPost controller, you gain full control over the post-authentication experience.