Strahinja Ajvaz
Strahinja Ajvaz

Reputation: 2633

password validation with yup and formik

how would one go about having password validation but at the same time having the errors be passed to different variables?

i.e

password: Yup.string().required("Please provide a valid password"),
passwordMin: Yup.string().oneOf([Yup.ref('password'), null]).min(8, 'Error'),
passwordLC: Yup.string().oneOf([Yup.ref('password'), null]).matches(/[a-z]/, "Error" )
passwordUC: Yup.string().oneOf([Yup.ref('password'), null]).matches(/[A-Z]/, "Error" )

I cant get the binding of the password variables to bind with the password object

Upvotes: 46

Views: 98964

Answers (7)

Abhay Pandey
Abhay Pandey

Reputation: 11

validation rule for an email input field using a validation library like Yup

const phoneRegex = /^\(?([6-9]{1})\)?[-. ]?([0-9]{4})[-. ]?([0-9]{5})$/;

 mobile: yup.string().matches(phoneRegex, "Invalid Phone Number"),
email: yup.string()
  .matches(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}$/i, 'Invalid email format')
  .required('Email is required'),
password: yup.string()
  .required('Please Enter your password')
  .matches(
    /^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})/,
    "Must Contain 8 Characters, One Uppercase, One Lowercase, One Number and One Special Case Character"
  ),

Upvotes: 0

stasionok
stasionok

Reputation: 11

import * as yup from 'yup'

// add global method to check password strength 
yup.addMethod(yup.Schema, 'isPasswordStrong', function(options, errorMessage = 'password must me stronger') {
  return this.test('test-is-password-strong', errorMessage, function(value) {
    const {
      path,
      createError
    } = this

    let isStrong = true

    // if field optional
    if (typeof value = 'undefined') {
        return true
    }

    if (options?.minLowercase) {
      if (!/[a-z]/.test(String(value))) {
        isStrong = false
      }
    }
    if (options?.minUppercase) {
      if (!/[A-Z]/.test(String(value))) {
        isStrong = false
      }
    }
    if (options?.minNumbers) {
      if (!/\d/.test(String(value))) {
        isStrong = false
      }
    }
    if (options?.minSymbols) {
      if (!/\W/.test(String(value))) {
        isStrong = false
      }
    }

    return (
      isStrong ||
      createError({
        path,
        message: errorMessage
      })
    )
  })
})

yup.object({
  password: yup
    .string()
    .min(8, 'password must contain 8 or more characters with at least one of each: uppercase, lowercase, number and special')
    .isPasswordStrong({
      minUppercase: 1,
      minLowercase: 1,
      minNumbers: 1,
      minSymbols: 1
    }, 'password should contain at least 1 lower case letter, 1 upper case letter, 1 digit and 1 symbol')
    .required('field is mandatory')
  })
})

Upvotes: 0

Dmitry Krutkin
Dmitry Krutkin

Reputation: 139

import * as yup from "yup";

const passwordRules = /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{5,}$/;
// min 5 characters, 1 upper case letter, 1 lower case letter, 1 numeric digit.

export const basicSchema = yup.object().shape({
  email: yup.string().email("Please enter a valid email").required("Required"),
  age: yup.number().positive().integer().required("Required"),
  password: yup
    .string()
    .matches(passwordRules, { message: "Please create a stronger password" })
    .required("Required"),
  confirmPassword: yup
    .string()
    .oneOf([yup.ref("password"), null], "Passwords must match")
    .required("Required"),
});

Upvotes: 5

Alexandre Moreira
Alexandre Moreira

Reputation: 410

I use yup-password for this. Example:

import * as Yup from 'yup';
import YupPassword from 'yup-password';
YupPassword(Yup);

const requiredField = () => Yup.string().required('required');    
const passwordField = () =>
  requiredField()
    .min(
      8,
      'password must contain 8 or more characters with at least one of each: uppercase, lowercase, number and special'
    )
    .minLowercase(1, 'password must contain at least 1 lower case letter')
    .minUppercase(1, 'password must contain at least 1 upper case letter')
    .minNumbers(1, 'password must contain at least 1 number')
    .minSymbols(1, 'password must contain at least 1 special character');

In this example I'm validating for min number of characters, lower and uppercase chars, numbers and symbols, but you can add or remove specifications. You can set a maximum amount of chars, for instance.

The beauty of this library is that you get to specify the error message, and it also handles special characters for you, which is great because it saves you from using RegEx. Have fun!

Upvotes: 19

Harshal
Harshal

Reputation: 8310

Hope this helps:

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')
});

Upvotes: 55

Seva
Seva

Reputation: 1739

Just to elaborate on efleurine's answer.
You do not need to store each validation on the same field - you can chain them to get a full validation.

password: Yup.string()
  .required('No password provided.') 
  .min(8, 'Password is too short - should be 8 chars minimum.')
  .matches(/[a-zA-Z]/, 'Password can only contain Latin letters.')

Note how you still can specify individual messages for each failure.
Also, for the binding to work, make sure the form input you're binding to has an appropriate name attribute - in this case, password.

Upvotes: 74

efleurine
efleurine

Reputation: 176

I know you can chain validations together for the same element. If you are trying to do cross-validation then this article would help you. it about formik in react but I bet it would give you an idea how to solve your case.

https://itnext.io/simple-react-form-validation-with-formik-yup-and-or-spected-206ebe9e7dcc

Upvotes: 1

Related Questions