16

I am writing rest API using node , express web module. For validation I am using express-validator npm. I want to apply some validation rules on password field.

How can I achieve it using express-validator?

What validation rules I want to apply for password as:

  1. min 8 char long.
  2. At least one uppercase.
  3. At least one lower case.
  4. At least one special character.

I read in this link that there is a function available called regex() . So I tried it but not working at all.

My approach:

req.check("password", "Password should be combination of one uppercase , one lower case, one special char, one digit and min 8 , max 20 char long").regex("/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/", "i");

Error

enter image description here

In express-js they have listed all the methods but did not find method / trick which solve my problem.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Sunil Sharma
  • 1,297
  • 3
  • 17
  • 31
  • As per my research I found that it is possible using express-validator's custom validation function. But do I need to define 4 functions to check it or is there any regex pattern function is available ?? – Sunil Sharma Jan 13 '16 at 07:37
  • Your question doesn't show any research effort on your part. You're asking people to do your work for you. You subsequently found the `customValidators` option, but it's still unclear what you tried yourself, and where you got stuck. Looking at the documentation, checking against a regex seems trivial to me. – robertklep Jan 13 '16 at 09:11
  • https://github.com/mlabieniec/complexity This has a nice solution to build the RegEx – psuhas Aug 25 '16 at 21:18

8 Answers8

23

The link you're referring to is almost 3 years old. Since then, the API of validator changed.

To check against a regular expression, use .matches():

req.check("password", "...").matches(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/, "i");
robertklep
  • 198,204
  • 35
  • 394
  • 381
  • I have used 'matches()' in first attempt but I made a silly mistake. I put pattern in quotes. like ' req.check("password", "...").matches(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/, "i"); ' . – Sunil Sharma Jan 13 '16 at 10:03
  • now it is working. perfectly. :). Still I think my question does not fall in down vote bucket. In future definitely it will help others. – Sunil Sharma Jan 13 '16 at 10:05
  • 1
    @SunilSharma not anymore, no. I didn't downvote but I'll upvote to get it back to 0. – robertklep Jan 13 '16 at 10:06
  • @robertklep can you please explain the regex. –  Nov 13 '16 at 11:08
  • @dewnor check out [this page](http://www.rexegg.com/regex-lookarounds.html#password), which does a pretty good job explaining how something similar works :) – robertklep Nov 13 '16 at 11:21
11

I believe the accepted answer is outdated. RegExp and express-validator are not the best ways to validate passwords in 2017, as the obscurity of regular expressions makes the app unmaintainable and prone to bugs.

password-validator makes it easy to define password rules and maintain them. Here's a sample:

var passwordValidator = require('password-validator');

var schema = new passwordValidator();

schema
  .is().min(8)
  .is().max(100)
  .has().uppercase()
  .has().lowercase();

console.log(schema.validate(req.body.password)); // prints a boolean

PS: I'm the author of the password-validator.

tbking
  • 8,796
  • 2
  • 20
  • 33
6

Theres a new solution for this. From the documentation:

Check if a password is strong or not. Allows for custom requirements or scoring rules. If returnScore is true, then the function returns an integer score for the password rather than a boolean. Default options:

body('password').isStrongPassword({
  minLength: 8,
  minLowercase: 1,
  minUppercase: 1,
  minNumbers: 1,
  minSymbols: 1,
  returnScore: false,
  pointsPerUnique: 1,
  pointsPerRepeat: 0.5,
  pointsForContainingLower: 10,
  pointsForContainingUpper: 10,
  pointsForContainingNumber: 10,
  pointsForContainingSymbol: 10,
})
Huhngut
  • 402
  • 6
  • 13
  • its work!. Thank you so much. I want to understand more about it, but I can't find the docs. Do you have url to it? – Anji Apr 07 '22 at 10:34
  • Here you go: https://express-validator.github.io/docs/ – Huhngut Apr 08 '22 at 11:03
  • thank for replying, but I know that docs, what i mean is isStrongPassword function's doc. Do you have it? – Anji Apr 10 '22 at 15:55
  • 1
    Im sorry. I don't know any other docs. You can check the source code and take a look at the tests if there are any. But I think it should be pretty self-explanatory with the params I included – Huhngut Apr 11 '22 at 16:18
  • 3
    I found it again: https://github.com/validatorjs/validator.js#validators – Huhngut Apr 16 '22 at 06:19
5

Using the built in validators of express-validator I was able to use built in validators without a regex to check the password.

const validateStrongPassword = body("password")
  .isString()
  .isLength({ min: 8 })
  .not()
  .isLowercase()
  .not()
  .isUppercase()
  .not()
  .isNumeric()
  .not()
  .isAlpha();

This verifies that there is at least one non letter character, one lowercase letter, one uppercase letter, a minimum length and that there are letters in the password.

Chris Payne
  • 101
  • 1
  • 3
4

Chosen answer is incomplete as it's missing validation for special characters. Correct answer should be:

req.checkBody("password", "Password must include one lowercase character, one uppercase character, a number, and a special character.").matches(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/, "i");

Only real difference is that I added the (?=.*[^a-zA-Z0-9]) expression which ensures a user is using a character that's not a number or letter.

10000RubyPools
  • 1,182
  • 3
  • 11
  • 24
2
check(
      "password1",
      "Please enter a password at least 8 character and contain At least one uppercase.At least one lower case.At least one special character. ",
    )
.isLength({ min: 8 })
.matches(
          /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z\d@$.!%*#?&]/,
        )
May Noppadol
  • 638
  • 8
  • 9
0

In case you are using an array for validation and therefore the req object is not available, you can also do the following:

body('field_name').matches(/^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]{8,}$/, "i").withMessage('Password should be combination of one uppercase , one lower case, one special char, one digit and min 8 , max 20 char long'),
-2

matches method work but I think it's not a stable for this use case, I think you should use the custom() method my code's :

this method work with tow parameters first is the value of your fieldset that in check method for example check('name field or password field') and the second value is an object that includes req object and you can use them and return a true or false if your returned value is true it's ok but if you return false its problem and validation is failed.

I write code in different shapes.

router.post('/adduser', [check('name').isLength({
    min: 2,
    max: 25
}).withMessage('min character 2 nad max character 25').custom((value, {req}) => {
    return !req.body.name.match(/[^a-zA-Z]/g)
}).withMessage('please write a correct name'),
    check('family').isLength({
        min: 2,
        max: 25
    }).withMessage('min character 2 nad max character 25').custom((value, {req}) => {
        return !req.body.name.match(/[^a-zA-Z]/g)
    }).withMessage('please write a correct family'),
    check('number').custom((value, {req}) => {
    return !req.body.name.match(/[^a-zA-Z]/g)
})], (req, res, next) => {
    console.log(validationResult(req).errors)
})
saman
  • 35
  • 1
  • 4