Using regex to validate a password strength can be quite a handy trick where password requirements keep getting stricter. A typical scenario for a complex password in this day and age would be a password with a minimum of 8 characters, including uppercase, lowercase and special characters. I have also added some benchmarks based on the 1080ti GPU using hashcat. Trying to identify this using a programming language may require a few if statements and may end up in a bulky password validation function or method.
The patterns mentioned below can be used in a backed application as well as a JavaScript regex password checker on the client side.
Lets start simple and see how we can create some regex patterns to validate password.
In the subsequent examples we will be using the { } (Curly Braces) to match a particular character or character class a specific number of times. ie. a{5} match the letter a 5 times, or a{5,} match the letter a a minimum of 5 times, or a{5,10} match the letter ‘a’ a minimum of 5 times and a maximum of 10 times.
Enforce characters and length allowed
Exactly 8 Character Password with lowercase letters
^[a-z]{8}$
RegEx | Explanation |
---|---|
^ | match from the start of the string |
[a-z]{8} | a single character in the range between a and z exactly 8 times |
$ | match till the end of the string |
Minimum 8 and Maximum 10 Character Password with lowercase letters
^[a-z]{8,10}$
RegEx | Explanation |
---|---|
^ | match from the start of the string |
[a-z]{8,10} | a single character in the range between a and z 8 to 10 times |
$ | match till the end of the string |
Minimum 8 Character Password with lowercase letters
^[a-z]{8,}$
RegEx | Explanation |
---|---|
^ | match from the start of the string |
[a-z]{8,} | a single character in the range between a and z 8 times or more |
$ | match till the end of the string |
While 8 characters are required as a minimum you can accept longer input using this method.
Exactly 8 Character Password with lowercase or uppercase letters
While you can also use the ‘i’ flag with [a-z] I am going to use the expanded version in the examples below as [a-zA-Z]
^[a-zA-Z]{8}$
RegEx | Explanation |
---|---|
^ | match from the start of the string |
[a-zA-Z]{8} | a single character in the range between a to z, and/or A to Z, exactly 8 times |
$ | match till the end of the string |
Minimum 8 and Maximum 10 Character Password with lowercase or uppercase letters
^[a-zA-Z]{8,10}$
RegEx | Explanation |
---|---|
^ | match from the start of the string |
[a-zA-Z]{8,10} | a single character in the range between a to z, and/or A to Z, 8 to 10 times |
$ | match till the end of the string |
Minimum 8 Character Password with lowercase or uppercase letters
^[a-zA-Z]{8,}$
Exactly 8 Character Password with lowercase, uppercase letters and numbers
In the following examples you can use the meta sequence \d (which denotes numbers from 0 to 9) inside the character class in most scenarios, but for ease of understanding and compatibility I will use ‘0-9’
^[a-zA-Z0-9]{8}$
Minimum 8 and Maximum 10 Character Password with lowercase, uppercase letters and numbers
^[a-zA-Z0-9]{8,10}$
Minimum 8 Character Password with lowercase, uppercase letters and numbers
^[a-zA-Z0-9]{8,}$
8 Character Password with lowercase, uppercase or special characters
You can add the number range(ie. 0-9, adding numbers/digits) to the examples below to include numbers in them as well but I will leave that out as it would be a similar example.
^[a-zA-Z!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]{8}$
Using shorthand:
^[a-zA-Z[:punct:]]{8}$
Minimum 8 and Maximum 10 Character Password with lowercase, uppercase or special characters
^[a-zA-Z!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]{8,10}$
Minimum 8 Character Password with lowercase, uppercase or special characters
^[a-zA-Z!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]{8,}$
Enforce characters restrictions and length allowed
Now lets complicate things slightly. In the examples above you can use any of the allowed characters with the real enforcement applying to the number of characters in the input.
So if lower and uppercase letters were allowed either all lowercase or all uppercase letters would be valid.
While this would be fine in most instances you may require at least one lowercase or at least one uppercase letter to be included. For this we need to use a lookahead in our pattern to determine if this character is present.
Lets look at inputs with only 8 characters allowed but for more variations, change the values inside the Curly Braces.
Exactly 8 Character Password with lowercase, uppercase letters and at least one uppercase letter
^(?=.*?[A-Z])[a-zA-Z]{8}$
In this example lowercase letters are optional.
To give you an overview of whats going on here in order to understand the subsequent examples in this section. Omitting the lookahead, we have ^[a-zA-Z]{8}$ which means allow lowercase and uppercase letters with a minimum and maximum of 8 characters.
Simple right?, so the different now is that we add (?=.?[A-Z]) to the beginning which is a positive lookahead that will scan the string from the beginning (since we use .? which is lazy) to see if there is a upper case letter that is found.
In the example above you can change (?=.[A-Z]) to (?=.[a-z]) to enforce at least one lowercase letter.
Exactly 8 Character Password with lowercase, uppercase letters, numbers and at least one lowercase letter and one uppercase letter
^(?=.*?[a-z])(?=.*?[A-Z])[a-zA-Z0-9]{8}$
Here we add (?=.?[a-z]) and (?=.?[A-Z]) to the start of the pattern following ^ which will look for at least one lowercase letter and one uppercase letter.
In this example numbers are optional and the input can contain a mix of upper and lower case letters.
Exactly 8 Character Password with lowercase, uppercase letters, numbers and at least one lowercase letter, one uppercase letter and one number
^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9])[a-zA-Z0-9]{8}$
In this example none of the characters allowed [a-zA-Z0-9] are optional and atleast one of them must be used to create a 8 character string.
The use of ^(?=.?[a-z])(?=.?[A-Z])(?=.*?[0-9]) tells the regex engine to scan the string from the start and make sure that atleast one of the characters in the lookaheads exists in the string and all lookaheads are satisfied.
Exactly 10 Character Password with lowercase, uppercase letters, numbers, special characters and at least one lowercase letter, one uppercase letter, one number and one special character
^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9])(?=.*?[!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~])[a-zA-Z0-9!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]{10}$
Remember you can change the length of the input by modifying what is inside the Curly Braces at the end.
Making sure that at least one character from the accepted list is included will help to make a strong password, specially with the last example.
Exactly 8 Character input with one lowercase letter and one uppercase letter and any possible character accepted
With examples using the lookaheads above you can also have the overall character restriction open ended instead of restricting it. This would also allow for Unicode or any other possible characters except line breaks to be accepted in the validation process.
^(?=.*?[a-z])(?=.*?[A-Z]).{8}$
To point out the difference we basically used .{8} which means match any 8 characters. Again you can extend the length here by changing the parameters in the Curly Braces brackets.
Now lets look at how you can enforce particular password policies with a few examples. Remember that you can modify or extend the examples to suit your specific need.
Enforcing Specific Password Policy using Regex
Exactly 10 Character Password with lowercase, uppercase letters, and a minimum of 3 Uppercase letter
^(?=(?:[a-z]*[A-Z]){3}(?![a-z]*[A-Z]))[A-Za-z]{10}$
While we are building on the previous examples, as this is the first one of it’s kind let me try to briefly explain what is going on here.
We start at the beginning of the string and use a lookahead with two parts. The first part (?:[a-z]*[A-Z]){3} checks to see if given the entire string do we have any combinations where three uppercase characters will be among any lowercase characters in any order.
The second part (?![a-z]*[A-Z]) which is a negative lookahead, is used to do something similar but in this case we are looking to find if there is one more uppercase character and discard the string if we find it, ie the input has failed to match as we only allow 3 uppercase characters. Finally something familiar, [A-Za-z]{10} provided the previous lookahead matched, we match 10 valid characters from start to finish, and as we used ^ and $ in the pattern this will need to be the entire length of the input in order to match. Remember if you dont want to restrict what characters can be used you can also use, .{10} at the end to say after enforcing the 3 uppercase letters, the user can include any other character they want such as Unicode etc, but not a linebreak.
I also want to provide a variation to this pattern to give us a bit more flexibility with the accepted characters.
^(?=(?:[^A-Z]*[A-Z]){3}(?![^A-Z]*[A-Z]))[A-Za-z]{10}$
The difference from the previous pattern is that instead of (?:[a-z][A-Z]){3} I am using (?:[^A-Z][A-Z]){3} where [a-z] meant lower cases letters but with [^A-Z] we say anything that is not an uppercase letter. The Advantage here is that we can now control what characters are actually allowed at the very end with what goes in the square brackets ie. [A-Za-z].
Minimum 10 Character Password with lowercase, uppercase letters, digits, a minimum of 4 lowercase letters and minimum of 2 uppercase letters
^(?=(?:[^A-Z]*[A-Z]){2}(?![^A-Z]*[A-Z]))(?=(?:[^a-z]*[a-z]){4}(?![^a-z]*[a-z]))[A-Za-z0-9]{10,}$
Taking the same pattern from above and allowing any possible character beside a linebreak to be included in the string.
^(?=(?:[^A-Z]*[A-Z]){2}(?![^A-Z]*[A-Z]))(?=(?:[^a-z]*[a-z]){4}(?![^a-z]*[a-z])).{10,}$
Exactly 12 Character Password with lowercase, uppercase letters, digits, special characters, a minimum of 3 lowercase letters, minimum of 3 uppercase letters, minimum of 3 numbers and a minimum of 3 special characters
Since we have a requirement of 3 characters that are mandatory from 4 character classes, the input needs to be a minimum of 12 characters long. In the patterns below I have used {12} to set this constraint where we are making sure at least 12 characters are present. If you require a longer password simply add a range such as {12,15} for twelve to fifteen input length or {12,} for 12 or more.
^(?=(?:[^A-Z]*[A-Z]){3}(?![^A-Z]*[A-Z]))(?=(?:[^a-z]*[a-z]){3}(?![^a-z]*[a-z]))(?=(?:[^0-9]*[0-9]){3}(?![^0-9]*[0-9]))(?=(?:[^!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]*[!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]){3}(?![^!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]*[!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]))[A-Za-z0-9!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]{12}$
Taking the same pattern from above and allowing any possible character beside a linebreak to be included in the string.
^(?=(?:[^A-Z]*[A-Z]){3}(?![^A-Z]*[A-Z]))(?=(?:[^a-z]*[a-z]){3}(?![^a-z]*[a-z]))(?=(?:[^0-9]*[0-9]){3}(?![^0-9]*[0-9]))(?=(?:[^!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]*[!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]){3}(?![^!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~]*[!"#\$%&'\(\)\*\+,-\.\/:;<=>\?@[\]\^_`\{\|}~])).{12}$