Search code examples
javascriptfirebasefirebase-authentication

Firebase Auth - createUserWithEmailAndPassword() - prevent login until email is verified


I wish to create a user account in Firebase Auth using createUserWithEmailAndPassword() - without logging in the user. I wish for the user to verify the email address first. Signing in the user directly causes a lot of unwanted side effects.

The /signup page has the following code - I wish for the user to stay on the /signup page after registration to be able to see the registration message.

firebase.auth().createUserWithEmailAndPassword(data.email, data.password)
.then((user)=> {
  //Send email verification link
  user.sendEmailVerification()
  //Show message - "Your account was created - please verify using link in email"
  handleStatusMessage(AUTH_SUCCESS)
})
.catch((error)=>{...})

The app.js has the following login and redirect handler

//handle login and redirect
firebase.auth().onAuthStateChanged((user) => {
  if (user) {
    if(!user.emailVerified){
      //Exit if email is not verified
      console.log('auth.js exit')
      //Line 7
    }
    store.dispatch(setInitialStore()).then(() => {
      renderApp()
      //Brings user to start page
      if (history.location.pathname === '/login') {
        history.push('/start')
      }
    })
} else {
  renderApp()
  //Brings user to /login or /verifyEmail page when logged out
  if(!history.location.pathname.includes('/verifyEmail')){
    history.push('/login')
  }  
}

My problems are:

  1. The user gets redirected after successful signup unless I cancel execution on line 7

  2. If I cancel execution on line 7, the user gets stuck when moving away from /signup

  3. Logging out the user causes the onAuthStateChanged() to trigger twice - redirecting the user

How can I keep the user on the /signup page after successful account creation while still allowing the user to navigate to the /login /verifyEmail location? Preferably in logged out state.


Solution

  • What I ended up doing was adding checks for when the user was logged in and logged out during signup.

    signupPage.js

    firebase.auth().createUserWithEmailAndPassword(data.email, data.password)
    .then((user)=> {
      //Login is triggered --> line 4 in app.js
      user.sendEmailVerification() //Send email verification
      handleStatusMessage(AUTH_SUCCESS) //Show success message
      firebase.auth().signOut() //Logout is triggered --> line 16 in app.js
    })
    .catch((error)=>{ ... }
    

    app.js

    //handle login and redirect
    firebase.auth().onAuthStateChanged((user) => {
      if (user) {
        //** line 4 ** EXIT if logged in from /signup
        if(!isEmailVerified && history.location.pathname.includes('/signup')){
          return
        }
        store.dispatch(setInitialStore()).then(() => {
          renderApp()
          //Brings user to start page
          if (history.location.pathname === '/login') {
            history.push('/start')
          }
        })
    } else {
      //** line 16 ** EXIT if logged out from /signup
      if(history.location.pathname.includes('/signup')){
        return
      }
      renderApp()
      //Brings user to /login or /verifyEmail page when logged out
      if(!history.location.pathname.includes('/verifyEmail')){
        history.push('/login')
      }  
    }
    

    I really wish there was a option for createUserWithEmailAndPassword() to be able to automatically send the email verification email and not logging in the user to avoid this kind of cat-and-mouse game code. :)

    A separate method along the lines of createUserWithEmailAndPasswordEmailVerificationRequired() that automatically sends the email link and does not sign in the user would also work ;)