Solution 1:

Update 20161110 - original answer below

Also, check out this answer for a different approach.

Original answer

This is actually possible.

But not directly, the way to do it is to create a second auth reference and use that to create users:

var config = {apiKey: "apiKey",
    authDomain: "projectId.firebaseapp.com",
    databaseURL: "https://databaseName.firebaseio.com"};
var secondaryApp = firebase.initializeApp(config, "Secondary");

secondaryApp.auth().createUserWithEmailAndPassword(em, pwd).then(function(firebaseUser) {
    console.log("User " + firebaseUser.uid + " created successfully!");
    //I don't know if the next statement is necessary 
    secondaryApp.auth().signOut();
});

If you don't specify which firebase connection you use for an operation it will use the first one by default.

Source for multiple app references.

EDIT

For the actual creation of a new user, it doesn't matter that there is nobody or someone else than the admin, authenticated on the second auth reference because for creating an account all you need is the auth reference itself.

The following hasn't been tested but it is something to think about

The thing you do have to think about is writing data to firebase. Common practice is that users can edit/update their own user info so when you use the second auth reference for writing this should work. But if you have something like roles or permissions for that user make sure you write that with the auth reference that has the right permissions. In this case, the main auth is the admin and the second auth is the newly created user.

Solution 2:

Update 20161108 - original answer below

Firebase just released its firebase-admin SDK, which allows server-side code for this and other common administrative use-cases. Read the installation instructions and then dive into the documentation on creating users.

original answer

This is currently not possible. Creating an Email+Password user automatically signs that new user in.

Solution 3:

I just created a Firebase Function that triggers when a Firestore document is Created (with rules write-only to admin user). Then use admin.auth().createUser() to create the new user properly.

export const createUser = functions.firestore
.document('newUsers/{userId}')
.onCreate(async (snap, context) => {
    const userId = context.params.userId;
    const newUser = await admin.auth().createUser({
        disabled: false,
        displayName: snap.get('displayName'),
        email: snap.get('email'),
        password: snap.get('password'),
        phoneNumber: snap.get('phoneNumber')
    });
    // You can also store the new user in another collection with extra fields
    await admin.firestore().collection('users').doc(newUser.uid).set({
        uid: newUser.uid,
        email: newUser.email,
        name: newUser.displayName,
        phoneNumber: newUser.phoneNumber,
        otherfield: snap.get('otherfield'),
        anotherfield: snap.get('anotherfield')
    });
    // Delete the temp document
    return admin.firestore().collection('newUsers').doc(userId).delete();
});

You can Algo use functions.https.onCall()

exports.createUser= functions.https.onCall((data, context) => {
    const uid = context.auth.uid; // Authorize as you want
    // ... do the same logic as above
});

calling it.

const createUser = firebase.functions().httpsCallable('createUser');
createUser({userData: data}).then(result => {
    // success or error handling
});

Solution 4:

Here is a simple solution using web SDKs.

  1. Create a cloud function (https://firebase.google.com/docs/functions)
import admin from 'firebase-admin';
import * as functions from 'firebase-functions';

const createUser = functions.https.onCall((data) => {
  return admin.auth().createUser(data)
    .catch((error) => {
      throw new functions.https.HttpsError('internal', error.message)
    });
});

export default createUser;
  1. Call this function from your app
import firebase from 'firebase/app';

const createUser = firebase.functions().httpsCallable('createUser');

createUser({ email, password })
  .then(console.log)
  .catch(console.error);
  1. Optionally, you can set user document information using the returned uid.
createUser({ email, password })
  .then(({ data: user }) => {
    return database
      .collection('users')
      .doc(user.uid)
      .set({
        firstname,
        lastname,
        created: new Date(),
      });
  })
  .then(console.log)
  .catch(console.error);