Home > database >  Make users UID [Authentication] the same as the users - firestore database
Make users UID [Authentication] the same as the users - firestore database

Time:10-17

I need to make the users UID the same as the documents id.

ex:

In [Authentication], I have the user with the following info: email: [email protected] UID: U8EZAjrCWQRvll6CVmI6OpGZwcH3

In [Firestore database], I have a user collection. In the user collection, I have a document for each user.

I would like to have the document id be the same as the user id.

is this possible?

Below is the snip I have for creating users in [Authentication] and [Firestore database] user collection::

class FirebaseAuthProvider implements AuthProvider {
  @override
  Future<void> initialize() async {
    await Firebase.initializeApp(
      options: DefaultFirebaseOptions.currentPlatform,
    );
  }
  @override
  Future<AuthUser> createUser({
    required String email,
    required String password,
  }) async {
    try {
      await FirebaseAuth.instance.createUserWithEmailAndPassword(
        email: email,
        password: password,
      );
      final user = currentUser;
      if (user != null) {
        return user;
      } else {
        throw UserNotLoggedInAuthException();
      }
    } on FirebaseAuthException catch (e) {
      if (e.code == 'weak-password') {
        throw WeakPasswordAuthException();
      } else if (e.code == 'email-already-in-use') {
        throw EmailAlreadyInUseAuthException();
      } else if (e.code == 'invalid-email') {
        throw InvalidEmailAuthException();
      } else {
        throw GenericAuthException();
      }
    } catch (_) {
      throw GenericAuthException();
    }
  }  
}

Below is my FirebaseCloudStorage class

class FirebaseCloudStorage {
  final user = FirebaseFirestore.instance.collection('user');
  Future<CloudUser> createNewUser({
    required String userId,
    required String userState,
    required String userImage,
    required String userFirstName,
    required String userLastName,
    required String userCellNumber,
    required String userCity,
    required String userAreaCode,
    required String userAddress,
    required String userEmail,
  }) async {
    final document = await user.add({
      
      userIdColumn: userId,
      userStateColumn: userState,
      userImageColumn: userImage,
      userFirstNameColumn: userFirstName,
      userLastNameColumn: userLastName,
      userCellNumberColumn: userCellNumber,
      userCityColumn: userCity,
      userAreaCodeColumn: userAreaCode,
      userAddressColumn: userAddress,
      userEmailColumn: userEmail,
    });
    final fetchedUser = await document.get();
    return CloudUser(
      documentId: fetchedUser.id,
      userId: userId,
      userState: userState,
      userImage: userImage,
      userFirstName: userFirstName,
      userLastName: userLastName,
      userCellNumber: userCellNumber,
      userCity: userCity,
      userAreaCode: userAreaCode,
      userAddress: userAddress,
      userEmail: userEmail,
    );
  }

// singleton
  static final FirebaseCloudStorage _shared =
      FirebaseCloudStorage._sharedInstance();
  FirebaseCloudStorage._sharedInstance();
  factory FirebaseCloudStorage() => _shared;
}

Below is the sign up screen button that kicks off all the creation


  Future createUserAccount() async {
    if (_photo == null) return;
    try {
      setState(() {
        _isLoading = true;
      });
      await AuthService.firebase().createUser(
        email: _email.text,
        password: _password.text,
        // displayName: _userFirstName.text,   // not working
      );
 
      final userId = AuthService.firebase().currentUser?.id;
      final destination = 'user-profile-image/$userId';
      final ref = FirebaseStorage.instance.ref(destination);
      await ref.putFile(_photo!);
      imageUrl = await ref.getDownloadURL();
      _userService.createNewUser(
        userId: userId as String,
        userState: 'new',
        userImage: imageUrl as String,
        userFirstName: _userFirstName.text,
        userLastName: _userLastName.text,
        userCellNumber: _userCellphoneNumber.text,
        userCity: _userCity.text,
        userAreaCode: _userAreaCode.text,
        userAddress: _userAddress.text,
        userEmail: _email.text,
      );

      setState(() {
        _isLoading = false;
      });
      AuthService.firebase().sendEmailVerification();
      Navigator.of(context).pushNamed(verifyEmailRoute);
    } on WeakPasswordAuthException {
      await showErrorDialog(
        context,
        'Weak password',
      );
    } on EmailAlreadyInUseAuthException {
      await showErrorDialog(
        context,
        'Email is already in use',
      );
    } on InvalidEmailAuthException {
      await showErrorDialog(
        context,
        'This is an invalid email address',
      );
    } on GenericAuthException {
      await showErrorDialog(
        context,
        'Failed to register',
      );
    }
  }

CodePudding user response:

You can use a custom id for a document by using set instead of add and specifying the already existing user identifier. So in your createNewUser function you can do it like:

final document = await user.doc(userId).set({      
  userIdColumn: userId,
  userStateColumn: userState,
  userImageColumn: userImage,
  userFirstNameColumn: userFirstName,
  userLastNameColumn: userLastName,
  userCellNumberColumn: userCellNumber,
  userCityColumn: userCity,
  userAreaCodeColumn: userAreaCode,
  userAddressColumn: userAddress,
  userEmailColumn: userEmail,
});

Note: It might be a better solution to maintain your own user collection from a trusted environment on the server side and not from the client. For example you can use Firebase Authentication triggers to add / delete / modify user data whenever there is a change, for example a new user is signed up. This way you don't have to allow write operations to your user collection from the client.

CodePudding user response:

You can use an onCreate trigger on an authentication event.

If you are using cloud functions you can use the following code to create a new document in your user collection when a new authentication entry is created:

export const createUser = functions.auth
.user()
.onCreate(async (user) => {

// DataObject includes all the data, which should be stored in firestore
    const dataObject = {
        email: user.email,
    };

    await dbFirestore
        .collection('users')
        .doc(user.uid)
        .set(dataObject, {merge: true});
});

Information about triggers: https://firebase.google.com/docs/functions/auth-events

  • Related