'Create a user document onCreate and onUpdate that is in sync with the auth.user Firebase v9
How to securely create a user document onCreate that is in sync with the auth.user database in Firebase v9.
I think it wouldn't be secure to let a registered user create a user document. So I wrote a cloud function which triggers on auth.user onCreate functions.auth.user().onCreate().
But as I want my users to input a display name or other information on sign up, I also want them to be stored to both db entries as well. But I have a problem keeping them in sync as I can't await the onCreate() cloud function trigger and so don't know when I can update the user document with all the data that wasn't submitted by user().onCreate() like the displayName and so on.
I tried and searched everywhere. I can't believe this is not a standard feature and still a requested topic. This seems so basic.
Error
error FirebaseError: No document to update:
Sign Up function
interface SignUpFormValues {
email: string;
password: string;
confirm: string;
firstName: string;
lastName: string;
}
const handleSignUp = async (values: SignUpFormValues) => {
const { firstName, lastName, email, password } = values;
const displayName = `${firstName} ${lastName}`;
try {
setError("");
setLoading(true);
// Create User
const userCredential = await createUserWithEmailAndPassword(
auth,
values.email,
values.password
);
// -> Signed in
// Update Profile
const user = userCredential.user;
await updateProfile(user, {
displayName: displayName,
});
// IMPORTANT: Force refresh regardless of token expiration
auth.currentUser.getIdToken(true);
// Check if user document already exists
// Get the from cloud functions onCreate created user document -> currently having an error because the doc is no created yet
const docRef = doc(db, "users", user.uid);
const docSnap = await getDoc(docRef);
console.log("docSnap.exists()", docSnap.exists()); // currently false
console.log("docSnap.data()", docSnap.data());
// Update user document
const newUserData = {
displayName: displayName,
firstName,
lastName,
};
await updateDoc(docRef, newUserData);
// Send Email verification
await authSendEmailVerification(user);
// Logout
await logout();
navigate("/sign-up/email-verification", { state: values });
} catch (error: any) {
const errorCode = error.code;
const errorMessage = error.message;
console.log("error", error);
console.log("error", errorCode);
if (errorCode === "auth/email-already-in-use") {
const errorMessage =
"Failed to create an account. E-Mail address is already registered.";
setError(errorMessage);
console.log("error", errorMessage);
} else {
setError("Failed to create account.");
}
}
setLoading(false);
};
Cloud function which triggers the user onCreate
// On auth user create
export const authUserWriteListener = functions.auth
.user()
.onCreate(async (user, context) => {
console.log("user:", user);
const userRef = db.doc(`users/${user.uid}`);
await userRef.set({
email: user.email,
createdAt: context.timestamp,
firstTimeLogin: true,
});
return db.doc("stats/users").update({
totalDocsCount: FieldValue.increment(1),
});
});
Solution 1:[1]
I think it wouldn't be secure to let a registered user create a user document.
Why not? Security rules can be used so the user can update their own data only. So you can run updateProfile and updateDoc right after createUserWithEmailAndPassword.
I have a problem keeping them in sync as I can't await the
onCreate()cloud function trigger
If you still want to use Cloud functions, then you can use callable functions and create user account, update all the required information in it and then sign user in with client SDK. So on client side:
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();
const createNewUser = httpsCallable(functions, 'createNewUser');
createNewUser({ email, password, displaName, ...otherData })
.then((result) => {
// Read result of the Cloud Function. (user account is created)
// Sign user in with client SDK
});
Also checkout:
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Dharmaraj |
