1

I'm trying to implement a normal authentication system in my app, but I'd like to create a new field for each user that is the "uniqueName" so users can search and add each other in their friends list. I was thinking of adding a textField in the signup form for the uniqueName and updating my User class adding a new String in this way:

class User {
  String email;
  String name;
  String uniqueName;
  String userID;
  String profilePictureURL;
  String appIdentifier;

  ...
}

Now, since I have this method for the email&password signup:

static firebaseSignUpWithEmailAndPassword(String emailAddress,String password,File? image,String name,) async {
try {
  auth.UserCredential result = await auth.FirebaseAuth.instance
      .createUserWithEmailAndPassword(
          email: emailAddress, password: password);
  String profilePicUrl = '';
  if (image != null) {
    await updateProgress('Uploading image, Please wait...');
    profilePicUrl =
        await uploadUserImageToFireStorage(image, result.user?.uid ?? '');
  }
  User user = User(
      email: emailAddress,
      name: name,
      userID: result.user?.uid ?? '',
      profilePictureURL: profilePicUrl);
  String? errorMessage = await firebaseCreateNewUser(user);
  if (errorMessage == null) {
    return user;
  } else {
    return 'Couldn\'t sign up for firebase, Please try again.';
  }
}

how do I have to modify it in order to add this new field in the registration? Since I have to check that the uniqueName insert by the user is effectively unique before creating a new user in the database, what can I do?

Furthermore, I think that it would be cool if this check is made concurrently to the filling of the form, how can I do it? (this is not necessary)

Thanks everyone for the answers

Lorenzo Cutrupi
  • 626
  • 3
  • 13
  • The Firebase Realtime Database and Cloud Firestore are two separate databases. Please only mark your question with the relevant tag, not with both. – Frank van Puffelen Sep 20 '21 at 14:40

2 Answers2

4

You have to save your users in a collection, then check if uniqueName already exists in the collection. If it exists, return error.

Then when a new user account is created, save the uniqueName.

// this function checks if uniqueName already exists
Future<bool> isDuplicateUniqueName(String uniqueName) async {
  QuerySnapshot query = await FirebaseFirestore.instance
      .collection('PATH_TO_USERS_COLLECTION')
      .where('uniqueName', isEqualTo: uniqueName)
      .get();
  return query.docs.isNotEmpty;
}

// call the above function inside here.
static firebaseSignUpWithEmailAndPassword(String emailAddress, String password, File? image, String name,) async {
  if (await isDuplicateUniqueName(name)) {
    // UniqueName is duplicate
    // return 'Unique name already exists';
  }
  // ... the rest of your code. Go ahead and create an account.
  // remember to save the uniqueName to users collection.
Peter Obiechina
  • 2,686
  • 1
  • 7
  • 14
1

I suggest doing the following steps:

  1. Create your own users collection (for example users) in Firestore, which you might have done already. (I don't think that User is a good class name, since Firebase Authentication is using the same name. Try MyUser or something.)

  2. Add authentication triggers that will ensure that whenever a Firebase user is added or deleted, it will also be added to or deleted from users collection, use Firebase uid as identifier.

  3. Create a solution to check whether a uniqueName already exists in users collection. You can use a Firestore query, but in this case you have to allow unauthenticated access to read users, at least uniqueName field. (Since the user is not authenticated yet at this point.) A Firebase Cloud Function is another option.

  4. When users enter their desired uniqueName, run the check before creating Firebase user. You can do it when user enters this or when you start the signup process.

  5. If uniqueName is unique, you can try to create Firebase user. Be aware, this step can also fail (for example e-mail name taken etc.). Your users document will be created by the authentication trigger you set up in step 2.

  6. Finally, you have to store this uniqueName in users collection. At this point you will have uid of the newly created Firebase user, so you can use Firestore set command with merge option set to true, so you don't overwrite other data.

It is important to note that you can't guarantee that the Firebase trigger already created the new document in users by the time you arrive to point 6, it is very likely that the trigger is still working or not even started yet. That's why you have to use set both in the authentication trigger and in your own code that sets uniqueName: which "arrives" first, will create the document, and the second will update it.

Also, for the same reason, you have to allow inserts and updates into users collection with Firestore rules. This might sound a little scary, but keep in mind that this is only your own user list to keep track of uniqueName, and authentication is based not on this, but on Firebase Authentication's user management which is well protected.

Last comment: this is not a 100% solution. It is quite unlikely, but theoretically can happen, that some else reserves a uniqueName between you check whether it's unique and the user is actually created. To mitigate this, it is a good idead to make the check just before Firebase user is created. Even in this case a slight chance remains for duplicates.

Peter Koltai
  • 8,296
  • 2
  • 10
  • 20