Password policy validators 

TYPO3 ships with two password policy validators, which are both used in the default password policy.

CorePasswordValidator 

The \TYPO3\CMS\Core\PasswordPolicy\Validator\CorePasswordValidator validator has the ability to ensure a complex password with a defined minimum length and four individual requirements.

The following options are available:

minimumLength

minimumLength
type

int

Default

8

The minimum length of a given password.

upperCaseCharacterRequired

upperCaseCharacterRequired
type

bool

Default

true

If set to true at least one upper case character (A-Z) is required.

lowerCaseCharacterRequired

lowerCaseCharacterRequired
type

bool

Default

true

If set to true at least one lower case character (a-z) is required.

digitCharacterRequired

digitCharacterRequired
type

bool

Default

true

If set to true at least one digit character (0-9) is required.

specialCharacterRequired

specialCharacterRequired
type

bool

Default

true

If set to true at least one special character (not 0-9, a-z, A-Z) is required.

NotCurrentPasswordValidator 

The \TYPO3\CMS\Core\PasswordPolicy\Validator\NotCurrentPasswordValidator validator can be used to ensure, that the new user password is not equal to the old password. The validator must always be configured with the exclude action \TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyAction::NEW_USER_PASSWORD, because it should be excluded, when a new user account is created.

Third-party password validators 

The extension EXT:add_pwd_policy provides additional validators.

Custom password validator 

To create a custom password validator, a new class has to be added which extends \TYPO3\CMS\Core\PasswordPolicy\Validator\AbstractPasswordValidator . It is required to overwrite the following functions:

  • public function initializeRequirements(): void
  • public function validate(string $password, ?ContextData $contextData = null): bool

Please refer to \TYPO3\CMS\Core\PasswordPolicy\Validator\CorePasswordValidator for a detailed implementation example.

Using password policy validation in Extbase 

If you need to validate a plaintext password within Extbase, for example in a Data transfer object (DTO), you can call the \TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyValidator from within a custom validator, for example:

packages/my_extension/Classes/Domain/Validator/ExtbasePasswordPolicyValidator.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Domain\Validator;

use TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyAction;
use TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyValidator;
use TYPO3\CMS\Extbase\Validation\Validator\AbstractValidator;

class ExtbasePasswordPolicyValidator extends AbstractValidator
{
    protected function isValid(mixed $value): void
    {
        if (!is_string($value)) {
            return;
        }
        $passwordValidator = new PasswordPolicyValidator(PasswordPolicyAction::NEW_USER_PASSWORD);
        if (!$passwordValidator->isValidPassword($value)) {
            foreach ($passwordValidator->getValidationErrors() as $validationError) {
                $this->addError($validationError, 1774872344835);
            }
        }
    }
}
Copied!

The error code should be a unique integer. It is common practice in TYPO3 to use the current Unix timestamp in milliseconds when creating a new validator, as this provides a simple way to generate a unique value.

You can then use your custom Extbase validator in the DTO:

packages/my_extension/Classes/Domain/Model/Dto/UserRegistrationDto.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Domain\Model\Dto;

use MyVendor\MyExtension\Domain\Validator\ExtbasePasswordPolicyValidator;
use TYPO3\CMS\Extbase\Attribute\Validate;

class UserRegistrationDto
{
    #[Validate(ExtbasePasswordPolicyValidator::class)]
    public string $plainTextPassword = '';
    // Another validator for username
    public string $username = '';
}
Copied!

Validate a password manually in PHP 

You can use the \TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyValidator to validate a password using the validators configured in $GLOBALS['TYPO3_CONF_VARS']['SYS']['passwordPolicies'] .

The class cannot be injected as it must be instantiated with an action. Available actions can be found in enum EXT:core/Classes/PasswordPolicy/PasswordPolicyAction.php (GitHub).

Example:

In the following example a command to generate a public-private key pair validates the password from user input against the default policy of the current TYPO3 installation.

EXT:my_extension/Classes/Command/PrivateKeyGeneratorCommand.php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\Command;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyAction;
use TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyValidator;

#[AsCommand(
    name: 'myextension:generateprivatekey',
    description: 'Generates an encrypted private key',
)]
final class PrivateKeyGeneratorCommand extends Command
{
    // Implement class MyService
    public function __construct(private readonly MyService $myService)
    {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);
        $passwort = (string)$io->askHidden(
            'Please enter the password to encrypt the key',
        );
        $passwordValidator = new PasswordPolicyValidator(PasswordPolicyAction::NEW_USER_PASSWORD);
        $result = $passwordValidator->isValidPassword($passwort);
        if ($result === true) {
            $this->myService->generatePrivateKey($passwort);
            return Command::SUCCESS;
        }
        $io->error('The password must adhere to the default password policy.');
        return Command::FAILURE;
    }
}
Copied!

Events regarding password policy validation 

The following PSR-14 event is available: