<p>When setting a password during front end registration using the core <code>users/save-user</code> action, <a href="https://github.com/craftcms/cms/blob/6d73ac2bcd9be609e79028852711ac7c13c62309/src/controllers/UsersController.php#L1313" rel="nofollow noreferrer">Craft actually sets the <code>newPassword</code> attribute on the user model</a> under the hood, not the <code>password</code> attribute.</p>
<p><em>This means that you need to test the length for the <code>newPassword</code> attribute, not the <code>password</code> attribute, i.e.:</em></p>
<pre class="lang-php prettyprint-override"><code>if (mb_strlen($user-&gt;newPassword) &lt; 8) {
    $user-&gt;addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event-&gt;isValid = false;
  }
</code></pre>
<p>Another issue with your code is the <code>if ($user-&gt;password != $user-&gt;confirmPassword) {</code> conditional.</p>
<p>The user model doesn't actually have a <code>confirmPassword</code> attribute, so it's odd if you're not seeing an exception thrown here (are you using <a href="https://craftcms.com/knowledge-base/what-dev-mode-does" rel="nofollow noreferrer"><code>devMode</code></a> during development?). But regardless, the code is not going to work as intended.</p>
<p>Note that you also can't do <code>$user-&gt;addError('confirmPassword', ...)</code> – again, since the user model doesn't actually have that attribute; the <code>addError()</code> method only works with actual attributes.</p>
<p>Assuming <code>confirmPassword</code> is the name for an input in your registration form, you'll need to change your code to something like this (personally I think an if/else statement makes sense here, since you can't set separate errors on the model for the password and the &quot;confirm password&quot;):</p>
<pre class="lang-php prettyprint-override"><code>if (mb_strlen($user-&gt;newPassword) &lt; 8) {
    $user-&gt;addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event-&gt;isValid = false;
  } else if ($user-&gt;newPassword !== Craft::$app-&gt;getRequest()-&gt;getBodyParam('confirmPassword')) {
    $user-&gt;addError('password', Craft::t('yii', 'Passwords do not match'));
}
</code></pre>
<p>Beyond this, while doing custom validation in an <code>EVENT_BEFORE_VALIDATE</code> event handler should work, the recommended way to do custom validation in Craft is to add Yii validation rules via the <code>Element::EVENT_DEFINE_RULES</code> event. <a href="https://craftcms.com/docs/4.x/extend/extending-system-components.html#custom-validation-rules" rel="nofollow noreferrer">Check out this page in the official docs.</a></p>

CC BY-SA 4.0
2023-01-15T00:11:45.680Z
Wow, thanks for the detailed answer! My code was kind of hacked together from some old questions on here - shows I still have so much to learn. Thank you.
supazu
CC BY-SA 4.0
2023-01-14T20:30:28.377Z
2023-01-14T20:35:43.127Z
2023-01-14T20:35:43.127Z
Mats Mikkel Rummelhoff
<p>I'm trying to add some rules for users signing up. The first two (<code>fullName</code> and <code>email</code>) work fine. However, the password rules are triggered no matter what. Even if the passwords match and are over 8 characters, it still fails.</p>
<pre><code>Event::on(User::class, Model::EVENT_BEFORE_VALIDATE, static function (Event $event) {
  // If a user is already logged in we are not on the public registration page
  if (Craft::$app-&gt;getUser()-&gt;getIdentity()) {
    return;
  }
  $user = $event-&gt;sender;

  // Do the custom validation
  if (!$user-&gt;fullName) {
    $user-&gt;addError('fullName', Craft::t('yii', 'Please enter your name.'));
    $event-&gt;isValid = false;
  }

  if (!$user-&gt;email) {
    $user-&gt;addError('email', Craft::t('yii', 'Please enter a valid email.'));
    $event-&gt;isValid = false;
  }

  if (mb_strlen($user-&gt;password) &lt; 8) {
    $user-&gt;addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event-&gt;isValid = false;
  }

  if ($user-&gt;password != $user-&gt; confirmPassword) {
    $user-&gt;addError('confirmPassword', Craft::t('yii', 'Passwords do not match'));
    $event-&gt;isValid = false;
  }
});
</code></pre>
<pre><code>&lt;label for=&quot;password&quot;&gt;Password&lt;/label&gt;
&lt;input id=&quot;password&quot; name=&quot;password&quot; type=&quot;password&quot;&gt;
{{ user ? forms.errorsList(user.getErrors('password')) }}

&lt;label for=&quot;confirmPassword&quot;&gt;Confirm Password&lt;/label&gt;
&lt;input id=&quot;confirmPassword&quot; name=&quot;confirmPassword&quot; type=&quot;password&quot;&gt;
    {{ user ? forms.errorsList(user.getErrors('confirmPassword')) }}
&lt;/div&gt;
</code></pre>
<p>Can anyone spot what I'm missing?</p>

<modules>
Custom validation rules on user signup
# Custom validation rules on user signup

(Asked by: username_0 on 2023-01-14)

I'm trying to add some rules for users signing up. The first two (fullName and email) work fine. However, the password rules are triggered no matter what. Even if the passwords match and are over 8 characters, it still fails.
Event::on(User::class, Model::EVENT_BEFORE_VALIDATE, static function (Event $event) {
  // If a user is already logged in we are not on the public registration page
  if (Craft::$app->getUser()->getIdentity()) {
    return;
  }
  $user = $event->sender;

  // Do the custom validation
  if (!$user->fullName) {
    $user->addError('fullName', Craft::t('yii', 'Please enter your name.'));
    $event->isValid = false;
  }

  if (!$user->email) {
    $user->addError('email', Craft::t('yii', 'Please enter a valid email.'));
    $event->isValid = false;
  }

  if (mb_strlen($user->password) < 8) {
    $user->addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event->isValid = false;
  }

  if ($user->password != $user-> confirmPassword) {
    $user->addError('confirmPassword', Craft::t('yii', 'Passwords do not match'));
    $event->isValid = false;
  }
});

Password

{{ user ? forms.errorsList(user.getErrors('password')) }}

Confirm Password

    {{ user ? forms.errorsList(user.getErrors('confirmPassword')) }}


Can anyone spot what I'm missing?

**Tags:** modules


---

## 1 answers

### Answer by username_1 on 2023-01-14. Score: 1 | Accepted answer

When setting a password during front end registration using the core users/save-user action, Craft actually sets the newPassword attribute on the user model under the hood, not the password attribute.
This means that you need to test the length for the newPassword attribute, not the password attribute, i.e.:
if (mb_strlen($user->newPassword) < 8) {
    $user->addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event->isValid = false;
  }

Another issue with your code is the if ($user->password != $user->confirmPassword) { conditional.
The user model doesn't actually have a confirmPassword attribute, so it's odd if you're not seeing an exception thrown here (are you using devMode during development?). But regardless, the code is not going to work as intended.
Note that you also can't do $user->addError('confirmPassword', ...) – again, since the user model doesn't actually have that attribute; the addError() method only works with actual attributes.
Assuming confirmPassword is the name for an input in your registration form, you'll need to change your code to something like this (personally I think an if/else statement makes sense here, since you can't set separate errors on the model for the password and the "confirm password"):
if (mb_strlen($user->newPassword) < 8) {
    $user->addError('password', Craft::t('yii', 'Password must be more than 8 characters.'));
    $event->isValid = false;
  } else if ($user->newPassword !== Craft::$app->getRequest()->getBodyParam('confirmPassword')) {
    $user->addError('password', Craft::t('yii', 'Passwords do not match'));
}

Beyond this, while doing custom validation in an EVENT_BEFORE_VALIDATE event handler should work, the recommended way to do custom validation in Craft is to add Yii validation rules via the Element::EVENT_DEFINE_RULES event. Check out this page in the official docs.

> **Comments:**
> **username_0**: Wow, thanks for the detailed answer! My code was kind of hacked together from some old questions on here - shows I still have so much to learn. Thank you.  

---

