0

I have a react app with 2 components and a state that monitors whether or not the user has logged in or not. When the user has logged in successfully, the value of the state will change from "NotLoggedin" to the user's email, which will then display the user's information component and hide the "Login/Signin" component. When a user has successfully created their account, instead of being logged in automatically, they will have to manually log in. To achieve this, I try using the signOut() method right after the createUserWithEmailAndPassword. And while I successfully sign the user out, there is a brief moment where the user's information component is displayed before being replaced by the "signIn" component, which I don't want. Is there anyway we can avoid that brief transition? Thank you very much.

import MyAccountTitle from "./MyAccountTitle";
import classes from "./Style/MyAccount.component.module.css"
import Signin from "./SignIn"
import MyAccountDetailAccordion from "./MyAccountDetail.component";
import {useState, useEffect, useRef} from 'react'
import { auth } from "../../api/firebase.util"; 
import { createUserWithEmailAndPassword, signOut, signInWithEmailAndPassword, updateProfile} from "firebase/auth";
import { async } from "@firebase/util";



function MyAccount(props){
    
    const [LoginorRegister, SetState] = useState("Login")
    const [myAccountSelection, ChooseMenu] = useState("Personal Info")
    const [accountState, setAccountState] = useState("NotLoggedin")
    const [email, setEmail] = useState('')
    const [password, setPassword] = useState('')
    const [username, setUserName] = useState('')
    
    useEffect(()=>{
        auth.onAuthStateChanged(currentUser=>{
            if (currentUser){
                setAccountState(currentUser.email)
            }
            else{
                setAccountState("NotLoggedin")
            }  
        }) 
    }, [])

 

    const receivingEmailInput = (event)=>{
        setEmail(event.target.value)
    }


    const receivingPasswordInput = (event)=>{
        setPassword(event.target.value)
    }

    const receivingUserName = (event) =>{
        setUserName(event.target.value)
    }

    const creatingNewUser = async ()=>{
        await createUserWithEmailAndPassword(auth, email, password)
        await updateProfile(auth.currentUser, {
            displayName: username
        })
        await signOut(auth)
        
    }

    const signUserIn = async ()=>{
        const user = await signInWithEmailAndPassword(auth, email, password)
        
        
    }

    const signUserOut = async (event)=>{
        event.preventDefault()
        await signOut(auth)
        
    }
    
    

    const onSelectingLogin = ()=>[
        SetState("Login")
    ]
    const onSelectingRegister = ()=>{
        SetState("Register")
    }

    const onSelectingPersonalInfo = ()=>{
        ChooseMenu("Personal Info")
    }
    const onSelectingAddressList = ()=>{
        ChooseMenu("Address List")
    }
    const onSelectingPastOrders = ()=>{
        ChooseMenu("Past Orders")
    }

    const selectionMenuNotLoggedIn = [{text: "Login", function: onSelectingLogin}, {text: "Register", function: onSelectingRegister}]

    const selectionMenuLoggedIn = [{text: "Personal Info", function: onSelectingPersonalInfo}, {text: "Past Orders", function: onSelectingPastOrders}, {text: "Address List", function: onSelectingAddressList}, {text: "Sign Out", function: signUserOut}]



    return (
        <main className={classes.main} >
          <MyAccountTitle userName = {auth.currentUser?.displayName} signOut={signUserOut} chosenMenu = {accountState != "NotLoggedin" ? myAccountSelection : null} accountState = {accountState} menu={accountState === "NotLoggedin" ? selectionMenuNotLoggedIn : selectionMenuLoggedIn}/>

          {accountState === "NotLoggedin" ? <Signin receivingUserName={receivingUserName} receivingEmailInput={receivingEmailInput} receivingPasswordInput={receivingPasswordInput} creatingNewUser={creatingNewUser} signUserIn={signUserIn}  currentState={LoginorRegister} /> : <MyAccountDetailAccordion userName = {auth.currentUser.displayName}  currentState ={myAccountSelection}/> }
          
        </main>
    );
}

export default MyAccount
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I found an article here that seems to be the same case with your but in different context, so please take a look: https://stackoverflow.com/questions/73158512/prevent-firebase-automatic-signin-after-creating-a-new-user – An Nguyen Aug 02 '23 at 09:04
  • @AnNguyen Thank you for reaching out. I'll see if the solutions in the document work and reply later. – Trung Lương Aug 02 '23 at 09:13
  • "When a user has successfully created their account, instead of being logged in automatically, they will have to manually log in." This is not how most applications work, and definitely not how the client-side SDKs for Firebase work. Why do you want this flow, which requires your user to enter the same credentials multiple times in quick succession? – Frank van Puffelen Aug 02 '23 at 15:50
  • @FrankvanPuffelen Thank you for reaching out. In most of the websites I have visited, often after a user creates an account they will receive an email to verify their account. After they have verified their account, they will manually log in – Trung Lương Aug 02 '23 at 21:23
  • You're confusing two things here: **authentication** happens when a user prove who they are, which in this scenario is accomplished by providing an email address and a password. Only allowing access after they verified their email address is a common **authorization** step. In the Firebase logic the two are separate; the user is signed in once they provide their email address + password, but your app then chooses to not let them continue until they've also verified their email address - which is a property of their profile. – Frank van Puffelen Aug 02 '23 at 21:43
  • If you only want users that verified their email address to sign in, that is accomplished with the email link provider: https://firebase.google.com/docs/auth/web/email-link-auth --- For more on this, also see https://stackoverflow.com/questions/69376494/firebase-email-password-authentication-how-to-require-email-verification, https://stackoverflow.com/questions/69033735/firebase-auth-email-verification-is-useless-because-the-user-can-access-the-app, https://stackoverflow.com/questions/48028927/firebase-email-verification-at-signup and more – Frank van Puffelen Aug 02 '23 at 21:44
  • @FrankvanPuffelen Thank you for the clarification, I am a beginner so this distinction is quite new to me. Does firebase come with a way to integrate that authorization step? – Trung Lương Aug 02 '23 at 22:15
  • Did you read the links I shared? The last two show how to check that the user has verified their email address in client-side code. If you're using a Firebase product to store data and it support security rules, you can also check the verification in those security rules. If you're using a custom backend, you can decode the ID token for the user and check their email verification there as shown in the last link. – Frank van Puffelen Aug 02 '23 at 23:30

1 Answers1

0

Update following your comment:

With the createUserWithEmailAndPassword() it is not possible to avoid that the new user is automatically signed-in after the account creation is complete.

One way to circumvent that is to create the user account in the back end via a Cloud Function. Cloud Functions use the Admin SDK and you can therefore use the createUser() method in a Callable Cloud Function. You'll find a detailed explanation of this approach (including code) in the following article.


Initial answer

If I correctly understand your question you just need to choose the correct Authentication State Persistence for your use case.

As explained in the doc "for a web application, the default behavior is to persist a user's session even after the user closes the browser", but you can easily change the persistence in such a way the user will have to re-enter their user name/password each time they open the app (Persistence of type 'SESSION' or 'NONE', depending on your exact need).

For that, as shown in the doc, you have to use the firebase.auth().setPersistence method and either the browserSessionPersistence or the inMemoryPersistence.

Renaud Tarnec
  • 79,263
  • 10
  • 95
  • 121
  • Thank you for reaching out. My problem is more about how to prevent the default behavior of automatically loggin a new user in after createuserwithemailandpassword() without using the signOut() function – Trung Lương Aug 02 '23 at 09:36
  • Oh ok I understand! See the update to my answer. – Renaud Tarnec Aug 02 '23 at 09:44
  • I am thinking about getting current date and time every time the user signs in, converts it to GMT, then compare it to the creation time stored in the currentUser metadata. If they are equal, then the state change will not be triggered. I will test this first and test your solution. Thank you – Trung Lương Aug 02 '23 at 09:47