cms icon indicating copy to clipboard operation
cms copied to clipboard

[4.x]: Custom 2FA implementation not redirecting on CP login (shows undefined error)

Open ks-arshitk opened this issue 2 months ago • 4 comments

What happened?

Description

I have implemented a custom 2FA module in Craft CMS 4.15.2.
Frontend 2FA flow is working correctly, but on the Control Panel login, after entering a valid username & password, Craft should redirect to my custom 2FA screen.

Instead of redirecting, the CP shows a plain "undefined" error.
No errors appear in storage/logs/error.log or info.log.

The expected CP redirect page exists at: craft/modules/TwoFactorAuth/src/templates/index.twig

Steps to reproduce

  1. Create custom module (folder: modules/TwoFactorAuth)
  2. Enable 2FA for a user
  3. Login to Control Panel
  4. After entering credentials, instead of redirecting to two-factor-auth, CP shows "undefined"

Expected behavior

  • After CP login, Craft should redirect to: cpUrl('two-factor-auth')
  • The modules/TwoFactorAuth/templates/index.twig page should load normally.

Actual behavior

  • The CP shows "undefined" on white screen
  • No PHP/log errors
  • handleLoginAttempt() is triggered, but redirect does not render the template.

Module code

` class TwoFactorAuth extends Module { public static $instance; public function init() { parent::init();

    self::$instance = $this;

    Craft::setAlias('@twofactorauth', __DIR__);

    $this->setComponents([
        'twoFactor' => TwoFactor::class,
    ]);

    // Register URL rules
    Craft::$app->getUrlManager()->addRules([
        'two-factor-auth/verify-code' => 'two-factor-auth/auth/verify-code',
        'two-factor-auth/verify-link/<token:[a-zA-Z0-9]+>' => 'two-factor-auth/auth/verify-link',
    ], false);

    // Intercept login to check for 2FA
    Event::on(
        User::class,
        User::EVENT_AFTER_LOGIN,
        function(UserEvent $event) {
            $user = Craft::$app->users->getUserById($event->identity->id);

            if ($user) {
                // Get the service instance
                $service = self::getInstance()->twoFactor;

                // Handle the login attempt
                $service->handleLoginAttempt($user);
            }
        }
    );

    // Register CP template roots for Two Factor Auth module
    Event::on(
        View::class,
        View::EVENT_REGISTER_CP_TEMPLATE_ROOTS,
        function(RegisterTemplateRootsEvent $event) {
            $event->roots['two-factor-auth'] = __DIR__ . '/templates';
        }
    );
}

public static function getInstance(): ?TwoFactorAuth
{
    return self::$instance;
}

} `

` class TwoFactor extends Component { public static function handleLoginAttempt($user) { if (Craft::$app->session->get('skip2FACheck')) { return; }

    if (self::isTwoFactorEnabled($user)) {
        if (Craft::$app->getRequest()->getIsCpRequest()) {
            Craft::$app->response->redirect(UrlHelper::cpUrl('two-factor-auth'))->send();
        } else {
            Craft::$app->response->redirect(UrlHelper::siteUrl('two-factor-auth'))->send();
        }

        Craft::$app->session->set('pending2FAUserId', $user->id);

        self::generateAndSend2FAToken($user);

        Craft::$app->user->logout(false);
    }
}

} `

Craft CMS version

4.15.2

PHP version

8.0.30

Operating system and version

No response

Database type and version

mysql

Image driver and version

No response

Installed plugins and versions

ks-arshitk avatar Dec 05 '25 05:12 ks-arshitk

CMS-1707

linear[bot] avatar Dec 05 '25 05:12 linear[bot]

Instead of redirecting, the CP shows a plain "undefined" error.

Can you post a screenshot of that?

Is Dev Mode enabled?

brandonkelly avatar Dec 05 '25 20:12 brandonkelly

Yes, dev mode is enable

Image

ks-arshitk avatar Dec 08 '25 04:12 ks-arshitk

Open your browser’s Network tab and try again. Can you post a screenshot of the users/login request’s response data?

brandonkelly avatar Dec 09 '25 17:12 brandonkelly