2

I have this line of code in a web app (on Firebase):

registerWithEmailAndPassword(name, email, password);

An email, password and a name are provided, and a new user account is created when the code is executed. All this seems normal, but what is less expected (at least to me) is that shortly after I find myself having the UID of the newly created user as my firebase.auth().currentUser.uid.

I do not do anything to log in as this new user. So I wonder what is happening under the hood.

Any idea or explanation would be helpful.

Michel
  • 10,303
  • 17
  • 82
  • 179

1 Answers1

2

registerWithEmailAndPassword is not a built in Firebase SDK method according to the API Reference. However, based on the name of that method, it is probably implemented in a way that makes use of createUserWithEmailAndPassword (modern / legacy) and updateProfile (modern / legacy) under the hood.

Importantly, createUserWithEmailAndPassword both creates the new user AND signs them in immediately. Because a user has been signed in, any onAuthStateChanged (modern / legacy) listeners will fire and the Auth instance's currentUser (modern / legacy) property will return the user's details.


This registerWithEmailAndPassword function probably looks like:

// Modern Firebase Syntax
import { getAuth, createUserWithEmailAndPassword, updateProfile } from "firebase/auth";

export const registerWithEmailAndPassword = async (displayName: string, email: string, password: string) => {
  // gets default FirebaseAuth
  const auth = getAuth();

  // creates and signs in a new user with the given email and password, and grabs the new user's details
  const { user } = await createUserWithEmailAndPassword(auth, email, password);

  // update the user's details with their name
  await updateProfile(user, { displayName });
}
// Legacy Firebase Syntax
import * as firebase from "firebase";
import "firebase/auth";

export const registerWithEmailAndPassword = async (displayName: string, email: string, password: string) => {
  // gets default FirebaseAuth
  const auth = firebase.auth();

  // creates and signs in a new user with the given email and password, and grabs the new user's details
  const { user } = await auth.createUserWithEmailAndPassword(email, password);

  // update the user's details with their name
  await user.updateProfile({ displayName });
}

To adapt this code so that you can sign up another user instead of yourself, you need to initialize a second Firebase app in the background. As this second app will have its own authentication state, you can use it to create/update other users without affecting the user signed into the default app.

// Modern Firebase Syntax
import { getApp, getApps, initializeApp } from "firebase/app";
import { getAuth, createUserWithEmailAndPassword, updateProfile, signOut } from "firebase/auth";

// creates/reuses a secondary app as needed, based off the default app's configuration
// consider moving this to your 'firebase.ts' file
const getSecondaryApp = () => {
  return getApps().find(a => a.name === 'secondary')
    || initializeApp(getApp().options, 'secondary'); // .options is a copy of the object passed into the default app's initializeApp()
}

export const registerWithEmailAndPassword = async (displayName: string, email: string, password: string) => {
  // gets secondary FirebaseAuth
  const secondaryAuth = getAuth(getSecondaryApp());

  // creates and signs in a new user with the given email and password, and grabs the new user's details
  const { user } = await createUserWithEmailAndPassword(secondaryAuth, email, password);

  // update the user's details with their name
  await updateProfile(user, { displayName });

  // sign out the newly created user
  await signOut(secondaryAuth);

  // return the new user's info to the caller
  return user; // depending on use, consider returning user.toJSON()
}
// Legacy Firebase Syntax
import * as firebase from "firebase";
import "firebase/auth";

// creates/reuses a secondary app as needed, based off the default app, based off the default app's configuration
// consider moving this to your 'firebase.ts' file
const getSecondaryApp = () => {
  return firebase.apps.find(a => a.name === 'secondary')
    || firebase.initializeApp(firebase.app().options, 'secondary'); // .options is a copy of the object passed into the default app's initializeApp()
}

export const registerWithEmailAndPassword = async (displayName: string, email: string, password: string) => {
  // gets secondary FirebaseAuth
  const secondaryAuth = firebase.auth(getSecondaryApp());

  // creates and signs in a new user with the given email and password, and grabs the new user's details
  const { user } = await secondaryAuth.createUserWithEmailAndPassword(email, password);

  // update the user's details with their name
  await user.updateProfile({ displayName });

  // sign out the newly created user
  await secondaryAuth.signOut();

  // return the new user's info to the caller
  return user; // depending on use, consider returning user.toJSON()
}
samthecodingman
  • 23,122
  • 4
  • 30
  • 54
  • Indeed. I should have written: await auth.createUserWithEmailAndPassword(email, password);which is contained in my local implementation of registerWithEmailAndPassword. But the core question stays the same. – Michel Jan 27 '23 at 09:45
  • I do not use updateProfile in my implementation of registerWithEmailAndPassword. Nevertheless it does the Job, except for the fact that I am happy with only creating a user, I do not want to sign in as that new user. – Michel Jan 27 '23 at 09:58
  • I have answered the question as asked. `createUserWithEmailAndPassword` both creates the new user AND signs them in immediately. This "login after creation" cannot be avoided in the client SDKs but it can be worked around by initializing a secondary app instance. Take a look at the last code block of [this answer](https://stackoverflow.com/a/59812155/3068190) where it initializes a second background FirebaseApp based on the default called `fbWorkerApp` and uses it to handle the authentication flow leaving the original user alone. – samthecodingman Jan 27 '23 at 14:15
  • It did not seem clear to me how to apply the link you mention to my use case. But this one https://stackoverflow.com/questions/37517208/firebase-kicks-out-current-user lead me to a simple and good solution (createOtherUser .....). – Michel Jan 28 '23 at 03:59
  • @Michel I've adapted this answer to include the requirement to work in the background. – samthecodingman Jan 28 '23 at 06:46
  • Amazing solution, @samthecodingman! Thank you! I was beating my head against a wall thinking there was something wrong with my security rules because I didn't realize I was getting signed out and back in as a different user. I kind of hate that it works this way, but your workaround totally makes sense and has saved my sanity. – Nick Tiberi Jun 23 '23 at 00:09