Craft’s only password requirements are that it is between 6 and 160 characters long. I want to require my users to enter passwords that are at least 7 characters long, with at least one number and one capital letter.

Is it possible to enforce these stricter requirements, or do we have to wait for this feature request to be accepted?

up vote 9 down vote accepted

In Craft 2

Plugins have the power to enforce stricter password requirements using the users.onBeforeSetPassword event.

Add this code to your plugin’s primary class:

public function init()
{
    craft()->on('users.beforeSetPassword', array($this, 'onBeforeSetPassword'));
}

public function onBeforeSetPassword(Event $e)
{
    $user = $e->params['user'];
    $password = $e->params['password'];

    // Perform our custom validation logic here
    $validates = true;

    if (mb_strlen($password) < 7)
    {
        $validates = false;
    }
    else if (!preg_match('/(\d.*[A-Z]|[A-Z].*\d)/', $password))
    {
        $validates = false;
    }

    if (!$validates)
    {
        // Set $performAction = false so the password doesn't get saved
        $e->performAction = false;

        // Add a custom validation error on the user
        $user->addError('newPassword', 'Sorry but your password must contain an uppercase letter, a number, a haiku, a gang sign, hieroglyph, and the blood of a virgin.');
    }
}

In Craft 3

Craft 3 doesn't have a beforeSetPassword event, but you can pull the same thing off from your plugin's init() method using the User element's User::EVENT_BEFORE_VALIDATE event like so:

public function init()
{
    parent::init();

    Event::on(
        User::class,
        User::EVENT_BEFORE_VALIDATE,
        function (ModelEvent $event) {
            // Check if a new password was set on the user
            if ($event->sender->newPassword) {
                $password = $event->sender->newPassword;
                $errors = [];

                // Perform our custom validation logic here
                $validates = true;

                if (mb_strlen($password) < 7) {
                    $validates = false;
                    $errors[] = 'Too Short!';
                }
                else if (!preg_match('/(\d.*[A-Z]|[A-Z].*\d)/', $password)) {
                    $validates = false;
                    $errors[] = 'Too Simple!';
                }

                $event->isValid = $validates;

                if (!$validates) {
                    /** @var User $user */
                    $user = $event->sender;
                    foreach ($errors as $error) {
                        $user->addError('newPassword', $error);
                    }
                }
            }
        }
    );
}
  • I've adapted Brandon Kelly's answer into a plugin, craft-password-enforcer. – kotyy Sep 19 '16 at 19:05
  • @BrandonKelly is there a way to stop the default craft error displaying if the password is less then 6 characters? As it is confusing for the user to show one error stating it needs to be 6 then another error again if I set my default length to be higher than this (10 for example). – Terry Upton Oct 1 '16 at 21:28
  • @TerryUpton Good question. Right now I don't think that’s possible, unfortunately. – Brandon Kelly Oct 11 '16 at 16:45

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.