SudoModeRequiredEvent
New in version 12.4.32 / 13.4.13
This event was introduced by security advisory TYPO3-CORE-SA-2025-013 to address challenges with single sign-on (SSO) providers.
The PSR-14 event
\TYPO3\
is triggered before
showing the sudo-mode verification dialog
when managing backend user accounts.
This step-up authentication, introduced as part of the fix for TYPO3-CORE-SA-2025-013, helps prevent unauthorized password changes. However, it may pose challenges when using remote single sign-on (SSO) systems, which typically do not support a separate step-up verification process.
This event allows developers to skip / bypass the step-up authentication process and uses custom logic, such as identifying users authenticated through an SSO system.
See also
- The SudoModeVerifyEvent is triggered before verification of a submitted password.
Example: Use an event listener to skip step-up authentication for SSO users
The following example demonstrates how to use an event listener to skip step-up
authentication for be_
records that have an active is_
flag:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Vendor\MyExtension\EventListener\SkipSudoModeDialog:
tags:
- name: event.listener
identifier: 'ext-myextension/skip-sudo-mode-dialog'
Vendor\MyExtension\EventListener\StaticPasswordVerification:
tags:
- name: event.listener
identifier: 'ext-myextension/static-password-verification'
<?php
declare(strict_types=1);
namespace Vendor\MyExtension\EventListener;
use TYPO3\CMS\Backend\Hooks\DataHandlerAuthenticationContext;
use TYPO3\CMS\Backend\Security\SudoMode\Access\AccessSubjectInterface;
use TYPO3\CMS\Backend\Security\SudoMode\Access\TableAccessSubject;
use TYPO3\CMS\Backend\Security\SudoMode\Event\SudoModeRequiredEvent;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
final class SkipSudoModeDialog
{
public function __invoke(SudoModeRequiredEvent $event): void
{
// Ensure the event context matches DataHandler operations
if ($event->getClaim()->origin !== DataHandlerAuthenticationContext::class) {
return;
}
// Filter for TableAccessSubject types only
$tableAccessSubjects = array_filter(
$event->getClaim()->subjects,
static fn(AccessSubjectInterface $subject): bool => $subject instanceof TableAccessSubject,
);
// Abort if there are unhandled subject types
if ($event->getClaim()->subjects !== $tableAccessSubjects) {
return;
}
/** @var list<TableAccessSubject> $tableAccessSubjects */
foreach ($tableAccessSubjects as $subject) {
// Expecting format: tableName.fieldName.id
if (substr_count($subject->getSubject(), '.') !== 2) {
return;
}
[$tableName, $fieldName, $id] = explode('.', $subject->getSubject());
// Only handle be_users table
if ($tableName !== 'be_users') {
return;
}
// Skip if ID is not a valid integer (e.g., 'NEW' records)
if (!MathUtility::canBeInterpretedAsInteger($id)) {
continue;
}
$record = BackendUtility::getRecord($tableName, $id);
// Abort if any record does not use SSO
if (empty($record['is_sso'])) {
return;
}
}
// All conditions met — disable verification
$event->setVerificationRequired(false);
}
}
See also: StaticPasswordVerification example