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.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
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.logorinfo.log.The expected CP redirect page exists at:
craft/modules/TwoFactorAuth/src/templates/index.twigSteps to reproduce
modules/TwoFactorAuth)two-factor-auth, CP shows"undefined"Expected behavior
cpUrl('two-factor-auth')modules/TwoFactorAuth/templates/index.twigpage should load normally.Actual behavior
"undefined"on white screenhandleLoginAttempt()is triggered, but redirect does not render the template.Module code
`
class TwoFactorAuth extends Module {
public static $instance;
public function init()
{
parent::init();
}
`
`
class TwoFactor extends Component
{
public static function handleLoginAttempt($user)
{
if (Craft::$app->session->get('skip2FACheck')) {
return;
}
}
`
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