102
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.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Player Josu
  • 1,133
  • 2
  • 6
  • 6

5 Answers5

261

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')
});
Harshal
  • 7,562
  • 2
  • 30
  • 20
  • 3
    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? – Renan Souza Nov 11 '20 at 15:48
  • 12
    @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 }) })``` – Hammed Oyedele Nov 13 '20 at 13:59
  • 2
    @HammedOyedele please create a post instead of a comment so we can upvote it and perhaps become selected as the best answer. – Telmo Dias Nov 14 '20 at 23:14
  • 1
    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'), });``` – Chathuranga Kasthuriarachchi Dec 15 '21 at 05:13
  • 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_confirmation – Ozal Zarbaliyev Feb 21 '22 at 08:09
  • 4
    I would add a `.required()` to `passwordConfirmation` and remove the `null` value. Otherwise the form is valid when leaving the `passwordConfirmation` field empty. – Behemoth Sep 03 '22 at 10:44
  • This code gives me this error `No overload matches this call. Overload 2 of 2, '(enums: readonly (string | Reference | undefined)[], message?: Message<{ values: any; }> | undefined): StringSchema', gave the following error. Type 'null' is not assignable to type 'string | Reference | undefined'.ts(2769)` – Qasim Rizvi Mar 30 '23 at 11:45
  • @QasimRizvi Is there any response from yup on it ? – Yash Karanke Apr 11 '23 at 11:38
  • 1
    @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')` – Qasim Rizvi Apr 12 '23 at 13:29
75

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
    })
})
Telmo Dias
  • 3,938
  • 2
  • 36
  • 48
Hammed Oyedele
  • 1,030
  • 8
  • 10
  • 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: – pupo162 Sep 30 '21 at 09:32
35

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.')
});
aprilmintacpineda
  • 1,114
  • 13
  • 21
0
onSubmit={(values)=>{
            const {confirmPassword,...data}=values;
            console.warn(data)
        }}
        
  • Can you provide some explanation how this solves the OP's problem. [Explaining entirely code-based answers](https://meta.stackoverflow.com/q/392712/3124333) – SiKing Apr 20 '23 at 21:43
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.

Benji
  • 45
  • 8