reactjsnext.jsasync-awaitnext-authpg

How to wait my insert to be committed before continuing instructions?


I made a NextAuth authentication with credentials. It works fine when I use the LogIn page.

const handleSubmit = async (event:FormEvent) => {
    event.preventDefault();
    await signIn("credentials", { 
        username: inputs.username, 
        password: inputs.password, 
        callbackUrl: '/home',
    });
}

Then, I tried to make the user log in right after creating his account.

The form is working and the account is created in the database but the user is not automatically logged in and I get a credentials error.

I guessed that the newly created account was not committed to the database before my code tried to log in.

I added a setTimeout for the NextAuth SignIn function and it works fine. So my guess should be right but using setTimeout doesn't seem to be the right way to do it.

I try the await syntax to make the SignIn happen after the CreateUser() has finished. It doesn't work. I think this is the way but I have obviously misunderstood something.

const submitUser = async (userData: FormData) => {
    if (validatePass()) {
        await CreateUser(userData)
        signIn("credentials", { 
            username: userData.get("username"),
            password: userData.get("password"),
            callbackUrl: '/home',
        });
    }
}
export async function CreateUser(userData: FormData) {

    bcrypt.hash(userData.get("password") as string, 12, async function(err, hash) {
        try {
            await query(
                `INSERT INTO users(username, password) VALUES ($1, $2)`,
                [userData.get("username"), hash]
            )
        } catch(error) {
            return {
                message: "Error in insert"
            }
        }
    });
};

Solution

  • The issue is that the CreateUser function is passing a callback to bcrypt.hash(), but is returning before the callback is called. Thus, the API request returns before the row has been inserted to the database.

    Assuming you're using the bcrypt package from npm, it also allows you to just await its functions instead of passing a callback:

    export async function CreateUser(userData: FormData) {
      try {
        const hash = await bcrypt.hash(userData.get("password") as string, 12);
        await query(`INSERT INTO users(username, password) VALUES ($1, $2)`, [
          userData.get("username"),
          hash,
        ]);
      } catch (error) {
        return {
          message: "Error in insert",
        };
      }
    }
    

    After these changes, your snippet should work:

    await CreateUser(userData)
    await signIn("credentials", { 
        username: userData.get("username"),
        password: userData.get("password"),
        callbackUrl: '/home',
    });