Laravel password validation rule

145,586

Solution 1

I have had a similar scenario in Laravel and solved it in the following way.

The password contains characters from at least three of the following five categories:

  • English uppercase characters (A – Z)
  • English lowercase characters (a – z)
  • Base 10 digits (0 – 9)
  • Non-alphanumeric (For example: !, $, #, or %)
  • Unicode characters

First, we need to create a regular expression and validate it.

Your regular expression would look like this:

^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\x])(?=.*[!$#%]).*$

I have tested and validated it on this site. Yet, perform your own in your own manner and adjust accordingly. This is only an example of regex, you can manipluated the way you want.

So your final Laravel code should be like this:

'password' => 'required|
               min:6|
               regex:/^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\x])(?=.*[!$#%]).*$/|
               confirmed',

Update As @NikK in the comment mentions, in Laravel 5.5 and newer the the password value should encapsulated in array Square brackets like

'password' => ['required', 
               'min:6', 
               'regex:/^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\x])(?=.*[!$#%]).*$/', 
               'confirmed']

I have not testing it on Laravel 5.5 so I am trusting @NikK hence I have moved to working with c#/.net these days and have no much time for Laravel.

Note:

  1. I have tested and validated it on both the regular expression site and a Laravel 5 test environment and it works.
  2. I have used min:6, this is optional but it is always a good practice to have a security policy that reflects different aspects, one of which is minimum password length.
  3. I suggest you to use password confirmed to ensure user typing correct password.
  4. Within the 6 characters our regex should contain at least 3 of a-z or A-Z and number and special character.
  5. Always test your code in a test environment before moving to production.
  6. Update: What I have done in this answer is just example of regex password

Some online references

Regarding your custom validation message for the regex rule in Laravel, here are a few links to look at:

Solution 2

This doesn't quite match the OP requirements, though hopefully it helps. With Laravel you can define your rules in an easy-to-maintain format like so:

    $inputs = [
        'email'    => 'foo',
        'password' => 'bar',
    ];

    $rules = [
        'email'    => 'required|email',
        'password' => [
            'required',
            'string',
            'min:10',             // must be at least 10 characters in length
            'regex:/[a-z]/',      // must contain at least one lowercase letter
            'regex:/[A-Z]/',      // must contain at least one uppercase letter
            'regex:/[0-9]/',      // must contain at least one digit
            'regex:/[@$!%*#?&]/', // must contain a special character
        ],
    ];

    $validation = \Validator::make( $inputs, $rules );

    if ( $validation->fails() ) {
        print_r( $validation->errors()->all() );
    }

Would output:

    [
        'The email must be a valid email address.',
        'The password must be at least 10 characters.',
        'The password format is invalid.',
    ]

(The regex rules share an error message by default—i.e. four failing regex rules result in one error message)

Solution 3

Since Laravel version 8, you can use built-in password validation:

// Require at least 8 characters...
Password::min(8)

// Require at least one letter...
Password::min(8)->letters()

// Require at least one uppercase and one lowercase letter...
Password::min(8)->mixedCase()

// Require at least one number...
Password::min(8)->numbers()

// Require at least one symbol...
Password::min(8)->symbols()

or you can chain them all


use Illuminate\Validation\Rules\Password;

$rules = [
    'password' => [
        'required',
        'string',
        Password::min(8)
            ->mixedCase()
            ->numbers()
            ->symbols()
            ->uncompromised(),
        'confirmed'
    ],
]

Solution 4

A Custom Laravel Validation Rule will allow developers to provide a custom message with each use case for a better UX experience.

php artisan make:rule IsValidPassword

namespace App\Rules;

use Illuminate\Support\Str;
use Illuminate\Contracts\Validation\Rule;

class isValidPassword implements Rule
{
    /**
     * Determine if the Length Validation Rule passes.
     *
     * @var boolean
     */
    public $lengthPasses = true;

    /**
     * Determine if the Uppercase Validation Rule passes.
     *
     * @var boolean
     */
    public $uppercasePasses = true;

    /**
     * Determine if the Numeric Validation Rule passes.
     *
     * @var boolean
     */
    public $numericPasses = true;

    /**
     * Determine if the Special Character Validation Rule passes.
     *
     * @var boolean
     */
    public $specialCharacterPasses = true;

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        $this->lengthPasses = (Str::length($value) >= 10);
        $this->uppercasePasses = (Str::lower($value) !== $value);
        $this->numericPasses = ((bool) preg_match('/[0-9]/', $value));
        $this->specialCharacterPasses = ((bool) preg_match('/[^A-Za-z0-9]/', $value));

        return ($this->lengthPasses && $this->uppercasePasses && $this->numericPasses && $this->specialCharacterPasses);
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        switch (true) {
            case ! $this->uppercasePasses
                && $this->numericPasses
                && $this->specialCharacterPasses:
                return 'The :attribute must be at least 10 characters and contain at least one uppercase character.';

            case ! $this->numericPasses
                && $this->uppercasePasses
                && $this->specialCharacterPasses:
                return 'The :attribute must be at least 10 characters and contain at least one number.';

            case ! $this->specialCharacterPasses
                && $this->uppercasePasses
                && $this->numericPasses:
                return 'The :attribute must be at least 10 characters and contain at least one special character.';

            case ! $this->uppercasePasses
                && ! $this->numericPasses
                && $this->specialCharacterPasses:
                return 'The :attribute must be at least 10 characters and contain at least one uppercase character and one number.';

            case ! $this->uppercasePasses
                && ! $this->specialCharacterPasses
                && $this->numericPasses:
                return 'The :attribute must be at least 10 characters and contain at least one uppercase character and one special character.';

            case ! $this->uppercasePasses
                && ! $this->numericPasses
                && ! $this->specialCharacterPasses:
                return 'The :attribute must be at least 10 characters and contain at least one uppercase character, one number, and one special character.';

            default:
                return 'The :attribute must be at least 10 characters.';
        }
    }
}

Then on your request validation:

$request->validate([
    'email'    => 'required|string|email:filter',
    'password' => [
        'required',
        'confirmed',
        'string',
        new isValidPassword(),
    ],
]);

Solution 5

Sounds like a good job for regular expressions.

Laravel validation rules support regular expressions. Both 4.X and 5.X versions are supporting it :

This might help too:

http://www.regular-expressions.info/unicode.html

Share:
145,586
Bharanikumar
Author by

Bharanikumar

technical link click pannu pa Try pannunga

Updated on July 05, 2022

Comments

  • Bharanikumar
    Bharanikumar almost 2 years

    How to added password validation rule in the validator?

    Validation rule:

    The password contains characters from at least three of the following five categories:

    • English uppercase characters (A – Z)
    • English lowercase characters (a – z)
    • Base 10 digits (0 – 9)
    • Non-alphanumeric (For example: !, $, #, or %)
    • Unicode characters

    How to add above rule in the validator rule?

    My Code Here

    // create the validation rules ------------------------
        $rules = array(
            'name'             => 'required',                        // just a normal required validation
            'email'            => 'required|email|unique:ducks',     // required and must be unique in the ducks table
            'password'         => 'required',
            'password_confirm' => 'required|same:password'           // required and has to match the password field
        );
    
        // do the validation ----------------------------------
        // validate against the inputs from our form
        $validator = Validator::make(Input::all(), $rules);
    
        // check if the validator failed -----------------------
        if ($validator->fails()) {
    
            // get the error messages from the validator
            $messages = $validator->messages();
    
            // redirect our user back to the form with the errors from the validator
            return Redirect::to('home')
                ->withErrors($validator);
    
        }
    
  • Bharanikumar
    Bharanikumar almost 9 years
    is there a way to show the message like " password strength is wrong " for this validation error?
  • Mazzy
    Mazzy over 7 years
    In your regex, use a \x instead of \X since \X has no special meaning
  • Nik K
    Nik K about 6 years
    Laravel 5.6 requires the validation to be provided as an array: 'password' => [ 'required', 'min:6', 'regex:/^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\X])(?=‌​.*[!$#%]).*$/', 'confirmed', ],
  • Barry D.
    Barry D. almost 6 years
    Can't we get rid of the min:6 and specify that rule as part of the regex?
  • justrusty
    justrusty over 5 years
    Also, you can add the validation to your service provider in the boot method like Validator::extend('strong_password', function ($attribute, $value, $parameters, $validator) { return preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).‌​+$/', (string)$value); }, 'Please make a strong password with at least one uppercase and lowercase letter, one number and one special character'); and then reference it like 'required|strong_password|string|min:6|confirmed'
  • Derrick Miller
    Derrick Miller over 5 years
    I like this solution a lot better than the ones which put all of the rules in one long regex. This seems a lot easier to understand and maintain.
  • Vahid Alvandi
    Vahid Alvandi about 5 years
    also in laravel 5.5 you should use array
  • ManojKiran Appathurai
    ManojKiran Appathurai almost 5 years
    looks clean while you have splitted up the Regex patterns
  • Mark
    Mark almost 4 years
    white spaces are passing validation with this regex
  • Florian Falk
    Florian Falk almost 4 years
    At Laravel v7.25.0, PHP 7.4.9 this regex isn't working. The error "preg_match(): Compilation failed: escape sequence is invalid in character class at offset 46" is thrown.
  • Charlie Dalsass
    Charlie Dalsass over 3 years
    Aesthetics are much nicer with this answer. Someone is going to have to debug that regular expression (in accepted answer) - especially since it's obviously changing in different Larvel versions ... sure don't want it to be me! This should be accepted answer.
  • Buraco
    Buraco over 3 years
    that solution allows me to adapt different password policies in the same project. almost the best practice for me.
  • leo
    leo over 3 years
    Totally agree that this solution looks MUCH easier to read and understand if you're not a hardcore regex guru!
  • TGR
    TGR about 3 years
    This is what I went with. This is the most relevant answer for 8.x. Laravel docs are clear, this is the example Laravel shows on their site. Thanks!
  • Yohanim
    Yohanim about 3 years
    I think it should be a best answer which is a lot better to maintain
  • miken32
    miken32 almost 3 years
    A solution using Laravel 8's new rules was already posted, this answer doesn't add anything.