-
Notifications
You must be signed in to change notification settings - Fork 683
Open
Description
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