[4.x]: Custom 2FA implementation not redirecting on CP login (shows undefined error)
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
- Create custom module (folder:
modules/TwoFactorAuth) - Enable 2FA for a user
- Login to Control Panel
- 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.twigpage 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
Instead of redirecting, the CP shows a plain "undefined" error.
Can you post a screenshot of that?
Is Dev Mode enabled?
Yes, dev mode is enable
Open your browser’s Network tab and try again. Can you post a screenshot of the users/login request’s response data?