Firebase.default.auth().currentUser.uid is null after createUserWithEmailAndPassword() - firebase

I'm trying to create a new document on my "users" collection on Firebase for any new user created on the Signup screen for my React-Native app, and the document is supposed to include the new user's uid, first name, last name, phone number, and date of birth. The issue is, after I use createUserWithEmailAndPassword to create a user, when I try to grab the uid with currentUser.uid, I get the following error: null is not an object (evaluating '_Firebase.default.auth().currentUser.uid').
I've been experimenting with ways to get the new user's "uid" in the .then statement following createUserWithEmailAndPassword and also creating the new document within the .then statement but I haven't gotten any luck with that yet. How should I modify my code so that I'm able to successfully create a new "users" document after successfully creating a user?
Below is my code from my handleSignUp function that is called when my "Sign Up" button is clicked:
handleSignUp = () => {
Firebase.auth()
.createUserWithEmailAndPassword(this.state.email, this.state.password)
.then(() => this.props.navigation.navigate("Main"))
.catch((error) => this.setState({ errorMessage: error.message }));
if (Firebase.auth().currentUser.uid) {
const user = {
uid: Firebase.auth().currentUser.uid,
firstName: this.state.firstName,
lastName: this.state.lastName,
phone: this.state.phone,
email: this.state.email,
dob: this.state.dob
};
db.collection("users").doc(response.user.uid).set(user);
}
};

If you want to:
Create a user
Write their details to the database
Navigate to a new page
You'll need to make sure you do these steps in that order, and use the promises returned by each step to make sure things happen at the right time:
Firebase.auth()
.createUserWithEmailAndPassword(this.state.email, this.state.password)
.then((credentials) => {
const user = {
uid: credentials.user.uid,
firstName: this.state.firstName,
lastName: this.state.lastName,
phone: this.state.phone,
email: this.state.email,
dob: this.state.dob
};
return db.collection("users").doc(response.user.uid).set(user);
}).then(() => {
this.props.navigation.navigate("Main")
}).catch((error) => this.setState({ errorMessage: error.message }));

Related

Firebase Admin SDK NodeJS -- "There is no user record corresponding to the provided identifier." Error

Following the Firebase SDK docs on https://firebase.google.com/docs/auth/admin/email-action-links#generate_email_verification_link and getting the following error, which makes little sense as the function is triggered from the server environment using the authenticated admin.auth().
Might anyone know what is causing the issue?
Error from admin.auth().generateEmailVerificationLink : { Error: There is no user record corresponding to the provided identifier.
at FirebaseAuthError.FirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:42:28)
at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/srv/node_modules/firebase-admin/lib/utils/error.js:88:28)
at new FirebaseAuthError (/srv/node_modules/firebase-admin/lib/utils/error.js:147:16)
at Function.FirebaseAuthError.fromServerError (/srv/node_modules/firebase-admin/lib/utils/error.js:186:16)
at /srv/node_modules/firebase-admin/lib/auth/auth-api-request.js:1201:49
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
errorInfo:
{ code: 'auth/user-not-found',
message: 'There is no user record corresponding to the provided identifier.' },
codePrefix: 'auth' }
The code is just this:
exports = module.exports = functions.firestore
.document("xxx/{docId}")
.onCreate(async (snap, context) => {
let yyy = snap.data();
let { uid, userData } = yyy;
console.log("from sendEmailVerification, uid, userdata: ", userData);
const actionCodeSettings = {
url: `${emailConfirmationUrl}`,
handleCodeInApp: false
};
return admin.auth().generateEmailVerificationLink(userData.email, actionCodeSettings)
.then(async (link) => {
console.log("uid from generateEmailVerificationLink and email: ", uid, userData.email)
await admin.firestore().collection('users').doc(uid).set({
verificationLink: link,
emailVerified: false
}, { merge: true });
return emailfunc.sendCustomVerificationEmail(userData.email, link);
})
.catch((err) => {
console.error("Error from admin.auth().generateEmailVerificationLink :", err);
return Promise.reject(err);
});
});
You read the user's email address from the database (Firestore). That user account, however, doesn't exist in Firebase Auth. It must also exist in Firebase Auth if you wish to use APIs like getUser() and generateEmailVerificationLink(). Having it only in Firestore is not enough.

Using vuex, firestore, and createUserWithEmailAndPassword, how do I create a user profile collection when a user registers?

For the app I'm building, I want my users to have a profile created for them when they register; the profile would contain the user's username, email, and the uid created by firebase authentication. I've got the authentication portion using createUserWithEmailAndPassword to work on its own. I'm also able to create a "users" collection, capturing a username and the user's email, on its own as well. However, I'm running into trouble grabbing and saving the uid to the user's profile in the user's collection.
Here is the code I have at the moment:
import * as firebase from "firebase/app";
import db from "../../components/firebase/firebaseInit";
actions: {
registerUser({ commit }, payload) {
commit("setLoading", true);
commit("clearError");
firebase
.auth()
.createUserWithEmailAndPassword(payload.email, payload.password)
.then(user => {
commit("setLoading", false);
const newUser = {
email: user.email,
id: user.uid,
courses: []
};
commit("setUser", newUser);
db.collection("users")
.add({
username: payload.username,
email: user.email,
userId: user.uid
})
.then(() => {
console.log("New user added!");
})
.catch(err => {
console.log(err);
});
})
.catch(err => {
commit("setLoading", false);
commit("setError", err);
});
},
In the research I've done, I've found these suggested solutions:
Get Current User Login User Information in Profile Page - Firebase and Vuejs
Cloud Firestore saving additional user data
And this video:
https://www.youtube.com/watch?v=qWy9ylc3f9U
And I have tried using the set() method instead of add(), as well.
But none of them seem to work, for me at least.
Thank you in advance for your help.
And if you need to see any more code, just let me know.
You haven't shared the error message you get, but most probably the error comes from the fact that the createUserWithEmailAndPassword() method returns a UserCredential and not a User.
So you have to do as follows:
import * as firebase from "firebase/app";
import db from "../../components/firebase/firebaseInit";
actions: {
registerUser({ commit }, payload) {
commit("setLoading", true);
commit("clearError");
firebase
.auth()
.createUserWithEmailAndPassword(payload.email, payload.password)
.then(userCredential=> {
commit("setLoading", false);
const user = userCredential.user; // <-- Here is the main change
const newUser = {
email: user.email,
id: user.uid,
courses: []
};
commit("setUser", newUser);
return db.collection("users")
.add({
username: payload.username,
email: user.email,
userId: user.uid
});
})
.then(() => {
console.log("New user added!");
})
.catch(err => {
commit("setLoading", false);
commit("setError", err);
});
},

Is there a way to create Auth object and use that UID to create a doc with GeoFirestore

I am trying to create an Auth object in firebase that returns the User UID. I want to be able to create a document in my collection with that particuar UID but apparently geofirestore doesn't have a feature to add a document with a particular ID.
const storesCollection = geoFirestore.collection("retailers");
export const firstTimeStartCreateRetailer = ( email, password) => async dispatch => {
try {
const { user } = await auth.createUserWithEmailAndPassword(email, password);
await storesCollection.doc(user.uid).add({
coordinates: new firebase.firestore.GeoPoint(33.704381, 72.978839),
name: 'Freshlee',
location: 'F-11',
city: 'Islamabad',
inventory: [],
rating: 5,
categories: []
})
dispatch({ type: LOGIN, payload: { ...user } });
} catch (error) {
console.log(error)
}
};
this code is rejected because geoFirestore doesn't have the .doc(id) referencing feature. How can I achieve this.
You need to do
await storesCollection.doc(user.uid).set({...})
using the set() method. As a matter of fact, there is no add() method for a GeoDocumentReference and storesCollection.doc(user.uid) is a GeoDocumentReference.
The add() method is a method of a GeoCollectionReference.
Because storesCollection is a GeoCollectionReference, the API is not always the same as native Firestore references.
In your particular case, you get the document you want to write to using doc(id), but instead of using add(...) which is used on collections, you need to use set(...) instead to create/overwrite the data for that particular document.
await storesCollection.doc(user.uid).set({
coordinates: new firebase.firestore.GeoPoint(33.704381, 72.978839),
name: 'Freshlee',
location: 'F-11',
city: 'Islamabad',
inventory: [],
rating: 5,
categories: []
});

Reference.set failed: First argument contains undefined

I have created a firebase function that listen on onCreate event, however the DocumentSnapshot.data() is returning empty.
The function code is:
exports.createClientAccount = functions.firestore
.document('/userProfile/{userId}/clientList/{clientId}')
.onCreate(async (snap, context) => {
console.log('****snap.data(): ', snap.data()); //Showing Empty from the console.
return admin
.auth()
.createUser({
uid: context.params.clientId,
email: snap.data().email,
password: '123456789',
displayName: snap.data().fullName,
})
.then(userRecord => {
return admin
.database()
.ref(`/userProfile/${userRecord.uid}`)
.set({
fullName: userRecord.displayName, //ERROR here: Reference.set failed: First argument contains undefined
email: userRecord.email,
coachId: context.params.userId,
admin: false,
startingWeight: snap.data().startingWeight,
});
})
.catch(error => {
console.error('****Error creating new user',error);
});
});
The document IS created on the firebase database under
/userProfile/{userId}/clientList/{clientId}
clientId document created on the database
As per the documentation, onCreate listens when a new document is created and returns the snapshot of the data created through the DocumentSnapshot interface. However, I have checked from the console that snap.data() is empty. I don't understand why it is empty if the document is created successfully on the database.
image showing error returned by the functions when creating the userProfile
From the function code, return admin.auth.createUser({}) is creating the user as anonymous because snap.data().email is undefined, but it should create a non anonymous user.
First, please try to change document('/userProfile/{userId}/clientList/{clientId}') to document('userProfile/{userId}/clientList/{clientId}').
path should not start with /.
exports.createClientAccount = functions.firestore
.document('userProfile/{userId}/clientList/{clientId}')
At the end problem was that when I created the document with add({}) I was not including the fields in the instruction. This is the function that creates the client document and now the function gets triggered correctly.
async clientCreate(
fullName: string,
email: string,
startingWeight: number
): Promise<any> {
const newClientRef = await this.firestore
.collection(`userProfile/${this.userId}/clientList/`)
.add({
fullName,
email,
startingWeight: startingWeight * 1,
});
return newClientRef.update({
id: newClientRef.id
});
}
I was calling this.firestore.collection(...).add({}) with no fields, so when it happened, the cloud function got triggered and the DocumentSnapshot.data() was empty thus returning the Reference.set error. The cloud function createClientAccount is correct. Thanks.

Email/Password auth provider returns empty userRecord

I have a cloud function that is triggered by Auth user creation. I look up the user data (email, name, etc) to populate my DB. It suddenly stopped working for the 'email/password' Auth provider type. The admin.auth().getUser(uid) now returns a userRecord which contains undefined/null values for most fields. This seemingly stopped working out of nowhere in Production after functioning for several weeks, is there any possible explanation?
exports.createUser = functions.auth.user().onCreate((user) => {
return createEmailUser(user);
});
function createEmailUser(user) {
const uid = user.uid;
return admin.auth().getUser(uid)
.then(function(userRecord) {
console.log(userRecord);
const email = userRecord.email;
const fullName = userRecord.displayName;
admin.database().ref('users/' + uid).set({
email: email,
name: fullName
});
})
.catch(function(error) {
console.log("Error fetching user data:", error);
});
}
In the past, the userRecord object contains valid email and displayName values. Now, I see an object like this:
UserRecord {
uid: 'Lrtj8zafsnYjZl4ckMgwNkgEiVH2',
email: undefined,
emailVerified: false,
displayName: undefined,
photoURL: undefined,
phoneNumber: undefined,
disabled: false,
metadata:
UserMetadata {
creationTime: 'Wed, 09 Jan 2019 21:40:31 GMT',
lastSignInTime: null },
providerData: [],
passwordHash: undefined,
passwordSalt: undefined,
customClaims: undefined,
tokensValidAfterTime: 'Wed, 09 Jan 2019 21:40:31 GMT' }
As users are registered with Email/Password method, then there is only the email address available in userRecord. Other sign-in providers might have different data at user creation.
What you can do here is to check user data at profile creation, and update profile with updateUser if anything is missing:
function createEmailUser(user) {
const uid = user.uid;
admin.auth().updateUser(uid, {
phoneNumber: "+11234567890",
displayName: "Foo Bar"
})
.then(function(userRecord) {
console.log(userRecord);
})
.catch(function(error) {
console.log("Error fetching user data:", error);
});
}

Resources