13

I have a user management feature in my flutter app that uses firebase authentication. I can register new user accounts using firebase_auth's createUserWithEmailAndPassword() function.

return await FirebaseAuth.instance.
    createUserWithEmailAndPassword(email: email, password: password);

The problem is when the registration is successful it automatically authenticates my FirebaseAuth instance as the new user even though I am already logged in.

I came across this answer: Firebase kicks out current user but it's in javascript and has a slightly different api.

How can I do the equivalent in dart?

Swift
  • 3,250
  • 1
  • 19
  • 35

3 Answers3

33

Updated: firebase_core ^0.5.0 and firebase_auth ^0.18.0+1 has deprecated some of the old classes.

Below is code updated for firebase_core ^0.5.1 and firebase_auth ^0.18.2.

static Future<UserCredential> register(String email, String password) async {
    FirebaseApp app = await Firebase.initializeApp(
        name: 'Secondary', options: Firebase.app().options);
    try {
        UserCredential userCredential = await FirebaseAuth.instanceFor(app: app)
        .createUserWithEmailAndPassword(email: email, password: password);
    }
    on FirebaseAuthException catch (e) {
      // Do something with exception. This try/catch is here to make sure 
      // that even if the user creation fails, app.delete() runs, if is not, 
      // next time Firebase.initializeApp() will fail as the previous one was
      // not deleted.
    }
    
    await app.delete();
    return Future.sync(() => userCredential);
}

Original Answer

I experimented with the firebase authentication api and my current working solution is:

// Deprecated as of `firebase_core ^0.5.0` and `firebase_auth ^0.18.0`.
// Use code above instead.

static Future<FirebaseUser> register(String email, String password) async {
    FirebaseApp app = await FirebaseApp.configure(
        name: 'Secondary', options: await FirebaseApp.instance.options);
    return FirebaseAuth.fromApp(app)
        .createUserWithEmailAndPassword(email: email, password: password);
}

Essentially it comes down to creating a new instance of FirebaseAuth so the automatic login from createUserWithEmailAndPassword() do not affect the default instance.

Swift
  • 3,250
  • 1
  • 19
  • 35
  • SwiftingDuster - what is the package that creates 'FirebaseApp'? It doesn't seem to be a part of firebase_auth. – user1961 Aug 09 '19 at 16:10
  • Was it firebase_core? – user1961 Aug 09 '19 at 16:17
  • Yes its part of `firebase_core` – Swift Aug 09 '19 at 17:06
  • Thanks for taking the time to clarify. This works as written, but it looks like it 'switches' the firebase app globally so I'm prevented from recognizing onauthstatechanged on the initial firebase app when I login agin. Is there a way to switch it back from the `secondary` app? My use case is that we register in the background (via your process) and wait to be verified then login. We want to prevent them from logging in while unverified. – user1961 Aug 09 '19 at 17:16
  • Since your `onAuthStateChanged` is on the original firebase auth instance then you should be able to just login with it: `FirebaseAuth.instance.signInWithEmailAndPassword()`. There is no built in way within firebase auth to allow only verified user to login as the default behaviour is to login automatically when you register. The workaround I am using is to use cloud functions to register on behalf of the user using the Admin SDK, then for verification you probably have to store whether they are verified seperately, like in a database. – Swift Aug 10 '19 at 03:29
  • Is this still your recommended solution? Is the code still uptodate? – Darjusch Aug 01 '20 at 19:46
  • The firebase auth api has not changed since I submitted this answer so I believe it still works. I can't test it personally as I don't use this piece of code at the moment – Swift Aug 02 '20 at 04:25
  • `FirebaseApp.configure()` is deprecated in the latest firebase_core ^0.5.0, instead, use `Firebase.initializeApp(name: 'Secondary');` – adadion Oct 08 '20 at 08:39
  • Also don't forget to delete the second instance after using it to free up space and avoid any possible conflict. – adadion Oct 08 '20 at 08:43
  • Can anyone please explain what does this lasat line mean: Future.sync(() => userCredential) – Canada2000 Apr 28 '21 at 06:50
  • You can read more about `Future.sync` [here](https://api.dart.dev/stable/2.10.4/dart-async/Future/Future.sync.html). In this case it's a future that immediately resolves and return `userCredential`. Its only used to wrap `userCredentials` within a future to satisfy the return type of the function. – Swift Apr 30 '21 at 08:24
  • Great :) Works for me! – Al Mamun Jun 14 '21 at 07:19
5

Based on Swift's answer I post updated code for this work around.

  Future signUpWithEmailPasswordAdminPastor(String email, String password, String role, String nama, String keuskupan, String kevikepan, String paroki) async {
try {

  FirebaseApp tempApp = await Firebase.initializeApp(name: 'temporaryregister', options: Firebase.app().options);

  UserCredential result = await FirebaseAuth.instanceFor(app: tempApp).createUserWithEmailAndPassword(
      email: email, password: password);

  // create a new document user for the user with uid
  await DatabaseService(uid: result.user.uid).updateUserDataSelf(
      true,
      role,
      nama,
      keuskupan,
      kevikepan,
      paroki,
      '',
      DateTime.now(),
      DateTime.now());

  tempApp.delete();
  return 'OK';
} catch (e) {
  print(e.toString());
  return null;
}
}

Above code works for firebase_core: ^0.5.0 and firebase_auth: ^0.18.0+1.

adadion
  • 746
  • 1
  • 10
  • 24
0

If you don't want to initialize a second Firebase App, you can simply logout after creating the user. Like:

  Future<void> myRegisterFunction(...) async {
    // _auth being your FirebaseAuth.instance
    await _auth.createUserWithEmailAndPassword(...);
    await _auth.signOut();
  }