🀘

Adding extra fields to your authentication form

This guide shows you how to add extra fields to your sign up form if you need to collect more info than just the user's email and password. Extra fields will be persisted to your database and will be included in the auth.user object for easy access in any component that reads the authenticated user.

πŸ—£
Keep in mind that your code may look slightly different then the examples below, depending on your Divjoy export options. The main structure, variables, and function names should be the same though.

Update the AuthForm component

Make the following changes to your authentication form in src/components/AuthForm.js

  1. Find the signup function within the submitHandlersByType object. We need to update this function to pass along more than just email and pass to auth.signup(). You can see our updated version of this function below. Notice how we don’t need to specify the new field names, as we use javascript destructuring to create an object named otherFields that contains all other fields.
  2. signup: ({ email, pass, confirmPass, ...otherFields }) => {
      return auth.signup(email, pass, otherFields).then((user) => {
        // The rest of this code is the same ...
      });
    },
    Although we don't use confirmPass in the code above, we must include it so that it's not part of the otherFields object.
  3. Scroll down to onSubmit and update the function so that it passes all form data (the full data object) instead of just email and pass. It should become ...
  4. const onSubmit = (data) => {
      setPending(true);
    
      submitHandlersByType[props.type](data).catch((error) => {
        // The rest of this code is the same ...
      });
    };
    Notice how we no longer destructure data into { email, pass } in the function argument and we pass the full data object to submitHandlersByType[props.type](data).
  5. Add a new input to your auth form (src/components/AuthForm.js). In this example we'll be adding a "Name" input to our form built with Material UI. If you're using a different UI kit then make sure to follow the patterns you see in your existing code rather than pasting in this example directly.
<form onSubmit={handleSubmit(onSubmit)}>
  {["signup", "signin", "forgotpass"].includes(props.type) && (
    {/* Your email input is here ... */} 
  )}

  {/* This is the part you'll be adding */} 
  {["signup"].includes(props.type) && (
    <Grid item={true} xs={12}>
      <TextField
        variant="outlined"
        type="text"
        label="Name"
        name="name"
        placeholder="Name"
        error={errors.name ? true : false}
        helperText={errors.name && errors.name.message}
        fullWidth={true}
        inputRef={register({
          required: "Please enter your name",
        })}
      />
    </Grid>
  )}

  {/* The rest of your inputs are here */}
</form>

Update auth.js

Make the following changes your authentication logic in src/util/auth.js

  1. Update the signup function so that it accepts a 3rd argument called otherFields and then calls updateProfile at the end of the promise chain. In this example we're using Firebase. If you're using a different auth provider make sure to just add in the relevant changes.
  2. const signup = (email, password, otherFields) => {
    	return createUserWithEmailAndPassword(auth, email, password)
        .then(handleAuth)
        .then(() => {
    	    return updateProfile(otherFields)
        });
    };
    This creates the user and then calls our custom updateProfile function to add the extra fields to the user in our database.
  3. Scroll down to the updateProfile. We need to make a small change that ensures it's safe to call this function immediately after the new user has been created.
  4. // If using Firebase change the updateUser call to ...
    await updateUser(auth.currentUser.uid, data);
    
    // If using Auth0 move fetching of currentUser to above updateUser 
    // and modify updateUser to read from currentUser instead.
    const currentUser = await auth0.extended.getCurrentUser();
    await updateUser(currentUser.sub, data);
    This change ensures we're not relying on the user object in our useAuth hook's state, which is not guaranteed to have been populated yet due to updateProfile being called immediately after creation of the user.

  5. That's it! You should now be able to signup and see the extra form field persisted to your database.

A note about social auth

Social authentication (google, facebook, etc) does not submit your authentication form. If you're using social auth in your app and a user signs up via social auth then they won't have a chance to give you this extra data. You can deal with this in two ways:

  1. Also add this field to your user settings component so they can update their data on their settings page. This may work for you if it's not absolutely necessary that a user give you this extra info, but you still want to give them a way.
  2. Add a 2nd step in your signup flow where user enters this information. Whether a user signs up via email/pass or a social option they will go to this 2nd step. This is easily done by adding a new route, taking the user to it after authentication (done via the afterAuthPath prop on your AuthSection component), and then presenting them with a form. You may find your SettingsGeneral component to be a good form example to copy this case.

πŸ—£
Did you find this guide helpful? Anything confusing? Please reach out and let us know.