Yup schema validation password and confirmPassword doesn't work
Asked Answered
Z

7

110
import * as Yup from 'yup';
import User from '../models/User';

class UserController {
async store(req, res) {
const schema = Yup.object().shape({
  name: Yup.string().required(),
  email: Yup.string()
    .email()
    .required(),
  password: Yup.string()
    .required()
    .min(6),
});

if (!(await schema.isValid(req.body))) {
  return res.status(400).json({ error: 'Validation fails' });
}

const userExists = await User.findOne({ where: { email: req.body.email } });
if (userExists) {
  return res.status(400).json({ error: 'User already exists.' });
}
const { id, name, email, provider } = await User.create(req.body);
return res.json({ id, name, email, provider });
}

async update(req, res) {
const schema = Yup.object().shape({
  name: Yup.string(),
  email: Yup.string().email(),
  oldPassword: Yup.string().min(6),
  password: Yup.string()
    .min(6)
    .when('oldPassword', (oldPassword, field) =>
      oldPassword ? field.required() : field
    ),
  confirmPassword: Yup.string().when('password', (password, field) =>
    password ? field.required().oneOf([Yup.ref('password')]) : field
  ),
});

if (!(await schema.isValid(req.body))) {
  return res.status(400).json({ error: 'Validation fails' });
}

const { email, oldPassword } = req.body;
const user = await User.findByPk(req.userId);
if (user.email !== email) {
  const userExists = await User.findOne({
    where: { email },
  });
  if (userExists) {
    return res.status(400).json({ error: 'User already exists.' });
  }
}

if (oldPassword && !(await user.checkPassword(oldPassword))) {
  return res.status(401).json({ error: 'Password does not match.' });
}

const { id, name, provider } = await user.update(req.body);

return res.json({ id, name, email, provider });
  }  
}
export default new UserController();

Here it creates a normal user with the password 123456:

Here it should work, since the old password is the same as the password of the created user, and it should update the new password:

I want to try to understand how to make him understand the current password as oldpassword and update the password.

Zagazig answered 18/5, 2020 at 4:2 Comment(0)
T
275

Try this out:

import * as Yup from 'yup';

validationSchema: Yup.object({
  password: Yup.string().required('Password is required'),
  passwordConfirmation: Yup.string()
     .oneOf([Yup.ref('password'), null], 'Passwords must match')
});
Tennietenniel answered 31/7, 2020 at 7:21 Comment(9)
currently with this, when I change one of the inputs only the one being changed is validated, meaning that I need to change both to have the proper state, is there any way to force both to be checked when changing one?Cinchonine
@RenanSouza you can use test() method instead. Yup.object({ password: Yup.string().required('Password is required'), passwordConfirmation: Yup.string() .test('passwords-match', 'Passwords must match', function (value) { return this.parent.password === value }) })Smaragdite
@HammedOyedele please create a post instead of a comment so we can upvote it and perhaps become selected as the best answer.Touched
May be you guys have to put another required option for passwordConfirmation as well. Yup.object().shape({ password: Yup.string().required('Password is required'), passwordConfirmation: Yup.string() .required('Confirm password is required') .oneOf([Yup.ref('password'), null], 'Passwords must match'), });Jenna
I used this in express end it works no problem. But in vue js it doesn't work maybe because of reactivity and instead I use .test in vue js like this .test('confirmation', 'Passwords do not match', (value) => password.value === value). by the way there are two variable password and password_confirmationRestitution
I would add a .required() to passwordConfirmation and remove the null value. Otherwise the form is valid when leaving the passwordConfirmation field empty.Semiconscious
This code gives me this error No overload matches this call. Overload 2 of 2, '(enums: readonly (string | Reference<unknown> | undefined)[], message?: Message<{ values: any; }> | undefined): StringSchema<string | undefined, AnyObject, undefined, "">', gave the following error. Type 'null' is not assignable to type 'string | Reference<unknown> | undefined'.ts(2769)Bullins
@QasimRizvi Is there any response from yup on it ?Inclined
@YashKaranke I'm using it like this: passwordConfirmation: Yup.string().oneOf( [Yup.ref('password')], 'Passwords must match', ), and it's working for me perfectly. Note: I've removed null after Yup.ref('password')Bullins
S
85

Based on @anoNewb answer and the request made by @Renan,

Yup.object({
  password: Yup.string().required('Password is required'),
  passwordConfirmation: Yup.string()
    .test('passwords-match', 'Passwords must match', function(value){
      return this.parent.password === value
    })
})
Smaragdite answered 15/11, 2020 at 12:47 Comment(1)
The problem with this solution is that it gets called for every input, not only to changes of passwordConfirmation, and the value that gets passed is of that input. so for example, this fails:Riata
A
37

This is how I did it.

yup.object({
  password: yup
    .string()
    .required('Please enter your password.')
    .min(8, 'Your password is too short.'),
  retypePassword: yup
    .string()
    .required('Please retype your password.')
    .oneOf([yup.ref('password')], 'Your passwords do not match.')
});
Actinomycin answered 17/2, 2022 at 13:20 Comment(1)
This works. I noticed that oneOf does not trigger without required.Ethanol
I
1

Based on Harshal's answer above, but the API is a little different.

import * as Yup from 'yup';

validationSchema: Yup.object({
  password: Yup.string().required('Password is required'),
  passwordConfirmation: Yup.string()
     .oneOf([Yup.ref('password'), undefined], 'Passwords must match')
});

Notice it's undefined instead of null.

Alternatively you can skip the undefined all together:

import * as Yup from 'yup';

validationSchema: Yup.object({
  password: Yup.string().required('Password is required'),
  passwordConfirmation: Yup.string()
     .oneOf([Yup.ref('password')], 'Passwords must match')
});
Ician answered 7/9, 2023 at 8:17 Comment(0)
T
0

It seems in the latest version of Yup. Yup ^1.0.0

You no longer need to pass null as the second argument to yup.ref where the options arguments go: docs.

Here's how I would test the confirm password:

import * as Yup from 'yup';

validationSchema: Yup.object({
  password: Yup.string().required('Password is required').matches(
      /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*[\]{}()?"\\,><':;|_~`=+-])[a-zA-Z\d!@#$%^&*[\]{}()?"\\,><':;|_~`=+-]{12,99}$/,
      'Must contain at least 12 Characters, 1 Uppercase, 1 Lowercase, 1 Special Character, and 1 Number'
    ),
  passwordConfirmation: Yup.string()
     .oneOf([Yup.ref('password')], 'Passwords must match')
});

Note: I have added an extra .matches() regex in to the solution as for security most sites use some form of password validation.

Trinity answered 23/6, 2023 at 10:37 Comment(0)
C
0
Yup.object({
  password: Yup.string().required('Password is required'),
  passwordConfirmation: Yup.string()
yup.string().when('password', ([password], schema, options) => {
  if (password!= '') {
     // if the password filled but passwordConfirmation not then return 
     required message
    if (options.value == '') {
      return schema.required();
    } else {
 // if the password filled and passwordConfirmation then return mismatch 
  message
      return schema.oneOf([password], 'validations.mismatch');
    }
  } else {
    return schema;
  }
})
})
Coniology answered 20/1 at 19:31 Comment(0)
I
-1
onSubmit={(values)=>{
            const {confirmPassword,...data}=values;
            console.warn(data)
        }}
        
Imperturbable answered 19/4, 2023 at 11:46 Comment(1)
Can you provide some explanation how this solves the OP's problem. Explaining entirely code-based answersAvert

© 2022 - 2024 — McMap. All rights reserved.