This question already has answers here:
Firestore- checking if username already exists [duplicate]
(1 answer)
Firestore unique index or unique constraint?
(5 answers)
Check a document field for a specific value in Cloud Firestore
(3 answers)
Closed 1 year ago.
I need a littel help with Firestore. I have a users data collection, user id-documents with each user information. I want to check if username already exists; // "That username already exists". How do I do it?
const signUpForm = document.querySelector('#signup-form');
signUpForm.addEventListener('submit', (evt) =>{
evt.preventDefault();
//get user email, password
const email= signUpForm['signup-email'].value;
const password = signUpForm['signup-password'].value;
const repassword = signUpForm['signup-re-password'].value;
if(password != repassword)
{
alert("Passwords don't match \nPlease try again");
}
else{
if(//check username exist?)
{
alert('This username already exist !');
}
else { //sign up the user
auth.createUserWithEmailAndPassword(email, password)
.then(cred => {
return db.collection('users').doc(cred.user.uid).set({
neptun: signUpForm['signup-neptun'].value,
nickName: signUpForm['signup-nickName'].value
});
});
}
});
Update!
A working solution :
const username = signUpForm['signup-username'].value;
db.collection("users").where("username", "==", username).get().then((doc) => {
if(!doc.empty) {
alert("This username is already taken!");
}
else{
//sign up the user
});
To be straight forward you can just try this code:
const username = ""
const userNameDoc = await firebase.firestore().collection("users").where("username", "==", username).get()
if(!userNameDoc.empty) {
console.log("This username is already taken!");
}
But as this is all frontend so this can be bypassed if anyone wants to. All this requires you to give all users access to the whole users collection which won't be ideal. So you should ideally use a cloud function or you own server environment for better security.
For example, you can block all direct requests to Firestore collection using security rules and create users using the Admin SDK in cloud functions.
You can use the code below in your cloud function to create a new user by checking if the username is still valid.
exports.createNewUser = functions.https.onCall(async (data, context) => {
const userEmail = data.email
const userName = data.name
const userPass = data.password
const userNameDoc = await admin.firestore().collection("users").where("username", "==", username).get()
if(!userNameDoc.empty) {
console.log("This username is already taken!");
return {result: "Username is already taken!"}
}
return admin
.auth()
.createUser({
email: 'user#example.com',
password: userPassword,
displayName: userName,
})
.then((userRecord) => {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully created new user:', userRecord.uid);
return {result: "User Created!"}
})
.catch((error) => {
console.log('Error creating new user:', error);
return {result: error}
});
});
The 2nd method is way more secure than first one for your Firestore DB.
Firebase automatically checks if an email is already in use.
The createUserWithEmailAndPassword function throws an error, when a user tries to sign up with an email address already in use.
Catch errors and then check for the "auth/email-already-in-use" error code:
.catch(function(error){
if(error.code=="auth/email-already-in-use"){//do something}
})
For more details, see the firebase auth reference https://firebase.google.com/docs/reference/js/firebase.auth.Auth?authuser=1#createuserwithemailandpassword
Related
I am currently working developing a login screen where I am using djoser for authentication.
I already use the /users/ and /token/login/ endpoints to create and log in users respectively in the frontend (JS fetch) and I know that /users/ will return an error message if the user already exists (which I'm displaying with react-hook-form).
My question is: is there a way of verifying if the user already exists with their email only (without trying to create an account and working it out from the error message)
From what I've found, Djoser doesn't provide a way to check if the email exists, so I wrote an APIView
class CheckEmail(APIView):
permission_classes = [IsAuthenticatedOrReadOnly]
def get(self, request, format=None):
email = request.GET.get('email')
user = UserAccount.objects.filter(email=email)
if user:
return Response('Email exists')
else:
return Response('Welcome aboard!')
and used a get request with Yup and Formik:
const LoginSchema = Yup.object().shape({
checkEmail: Yup.boolean().default(true),
email: Yup.string()
.email("Please enter valid email")
.required("Email is required")
.when("checkEmail", {
is: true,
then: Yup.string()
.test({
message: () => "Email already exists",
test: async(email) => {
if(email) {
try {
let response = await axios.get(`http://localhost:8000/accounts/users/check_email/?email=${email}`);
if (response.data === 'Welcome aboard!') {
return true;
} else {
return false;
}
} catch (error) {
//console.log(error);
}
}
}
})
}),
Hope that helps
This question already has answers here:
Cloud Firestore: Enforcing Unique User Names
(8 answers)
Closed 3 years ago.
What i'am attempting to do is create new users with Firebase authentication and create their own document entry within Firestore. So far everything went well until i wanted to create unique usersnames. What is the most optimal way of going about doing this? should i create an array of all the users to cross-reference upon each sign up, or perhaps create a collection dedicated to Usernames with their email attached (which you can see i did in the second call to Firebase)
Firebase auth takes in email and passwords only so thats out of the question, or at least from what i gather.
export const signInUser = async ({ name, email, password }) => {
try {
await firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(cred => {
return firebase
.firestore()
.collection("users")
.doc(cred.user.uid)
.set({
name: name,
email: email,
friends: []
});
});
await firebase
.firestore()
.collection("usernames")
.doc(name)
.set({ username: name, email: email });
firebase.auth().currentUser.updateProfile({
displayName: name
});
return {};
} catch (error) {
switch (error.code) {
case "auth/email-already-in-use":
return {
error: "E-mail already in use."
};
case "auth/invalid-email":
return {
error: "Invalid e-mail address format."
};
case "auth/weak-password":
return {
error: "Password is too weak."
};
case "auth/too-many-requests":
return {
error: "Too many request. Try again in a minute."
};
default:
return {
error: "Check your internet connection."
};
}
}
};
I'd skip the "usernames" collection here, as you're basically creating an index, which fireStore already does for you. To check whether a name is unique, you can do:
const snapshot = await firestore.collection("users").where("name", "==", name).get();
// The name is taken if snapshot.empty is false.
I'm trying to create a data entry on the firebase database to store additional information about a user when they register on my site.
I've tried to write data to the database in the .then() function following createUserWithEmailAndPassword() as that's the only way for me to extract the user id for the user (I'm hoping to use the uid as the key field of the record I create)
(req, res) => {
// extract user data from the form
const newUser = {
fname: req.body.fname,
lname: req.body.lname,
email: req.body.email,
pw: req.body.pw,
pw_c: req.body.pw_c
}
// carry out validation
const { valid, errors } = validateRegistrationData(newUser);
if (!valid) return res.status(400).json(errors);
// create new firebase user
firebase
.auth()
.createUserWithEmailAndPassword(newUser.email, newUser.pw)
.then(data => {
let uid = data.user.uid;
// make a database entry to store the users info
// by default, assumes that the user is a secondary user
let userData = {
fname: newUser.fname,
lname: newUser.lname,
email: newUser.email,
utype: 1,
createdon: admin.firestore.FieldValue.serverTimestamp(),
intitems: []
}
newUserDoc = db
.collection("users")
.doc(uid)
.set(userData)
return res.status(200).json("Success: new user created.");
})
.catch(err => {
if (err.code === "auth/email-already-in-use"){
return res.status(400).json({ email: "Email is already in use" });
} else {
return res.status(500).json({ error: err.code });
}
});
return res.status(200).json("Success: new user created.");
}
The server responds with {Success: new user created."}. The authentication part seems to work as a new user is created in the Authentication section of my firebase console. However, no new data entries appear in the users collection of my database.
.set returns a promise that still needs to run to completion. However, currently you're not waiting on the promise, and instead just responding via res.send.
You can append .then(() => { do stuff here }) to the end of .set. If it's the last thing you're doing in that function, you can just do res.send from there.
return db.collection("users").doc(uid).set(userData).then(() => {
return res.status(200).json("Success: new user created.");
})
.catch(error => {
console.log(error)
})
I am creating a form, in react-redux to change user password. I am wondering how can I validate the user current password in order to change to new one.
in my form I have 2 fields: old password, new password.
this is my action:
const { currentUser } = auth
currentUser.updatePassword(newPassword)
.then(
success => {
dispatch({
type: CHANGE_USER_PASSWORD_SUCCESS,
payload: currentUser
})
},
error => {
dispatch({
type: CHANGE_USER_PASSWORD_FAIL,
error: error.message
})
}
)
I am wondering, how to validate the old password in firebase? Should I use signInWithEmailAndPassword()? Or, is there a function to validate the current password without calling the signIn again, since my user is already logged in?
Thanks
Well, I believe you want the user to enter the old password just to verify whether it's the actual owner of the account or not.
Firebase handles this situation very well, you just need to call the updatePassword method on the user object and pass in the new password.
const changePassword = async newPassword => {
const user = firebase.auth().currentUser;
try {
await user.updatePassword(newPassword)
console.log('Password Updated!')
} catch (err) {
console.log(err)
}
}
If it's been quite a while that the user last logged in then firebase will return back an error -
"This operation is sensitive and requires recent authentication. Log in before retrying this request."
Thus, you don't really need to check the old password as firebase does it for you.
But if you just want to do it in one go, without having the user to log in again.
There's a way for that as well.
There is a method on user object reauthenticateAndRetrieveDataWithCredential you just need to pass in a cred object(email and password) and it refreshes the auth token.
const reauthenticate = currentPassword => {
const user = firebase.auth().currentUser;
const cred = firebase.auth.EmailAuthProvider.credential(
user.email, currentPassword);
return user.reauthenticateAndRetrieveDataWithCredential(cred);
}
In your particular case, you can have something like this
const changePassword = async (oldPassword, newPassword) => {
const user = firebase.auth().currentUser
try {
// reauthenticating
await this.reauthenticate(oldPassword)
// updating password
await user.updatePassword(newPassword)
} catch(err){
console.log(err)
}
}
Learn more about firebase reauth - https://firebase.google.com/docs/auth/web/manage-users#re-authenticate_a_user
Hope it helps
Here's my code in .js
$("#loginBtn").click(
function(){
var email = $("#loginEmail").val();
var password = $("#loginPassword").val();
if(email != "" && password != ""){
$("#loginProgress").show();
$("#loginBtn").hide();
$("#registerBtn").hide();
firebase.auth().signInWithEmailAndPassword(email,
password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
$("#loginError").show().text(errorMessage);
$("#loginProgress").hide();
$("#loginBtn").show();
$("#register_account_Btn").hide();
$("#back_btn").hide();
});
}
}
);
/* REGISTER PROCESS */
$("#register_account_Btn").click(
function () {
var email = $("#regEmail").val();
var password = $("#regPassword").val();
if(email != "" && password != ""){
$("#loginProgress").show();
$("#loginBtn").hide();
firebase.auth().createUserWithEmailAndPassword(email,
password).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
$("#loginError").show().text(errorMessage);
$("#loginProgress").hide();
$("#loginBtn").show();
$("#register_account_Btn").hide();
$("#back_btn").hide();
});
}
I found this on the internet but I don't know where to insert it.
Is this correct?
var uid = firebase.auth().currentUser.uid;
firebase.database().ref().child('accounts').child(uid).set({
email: user.email,
userId: uid
})
Should I create another function?
and these are the rules in my firebase database. Is it advisable to use this?
Additional Question:
I want to create a user roles: teacher and student. Teacher can create classroom, add students, view the list of students. While the student can view his/her classmates and teacher. How should I do this?
{
"rules": {
"users": {
"$uid": {
".read": false,
".write": "$uid === auth.uid"
}
}
}
}
Sincerest apology but I'm new to this ;(
The firebase.auth().createUserWithEmailAndPassword function returns a Promise: firebase.User.
You're only catching exceptions with your code, if you chain a .then onto the function you can get the user information and save that user to the data.
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => {
// Save user here.
return firebase.database().ref('/users/' + user.uid).set({
email: user.email,
uid: user.uid
});
})
.catch(function(error) {
// Handle Errors here.
});
Your other question around the teacher / student is very broad - try to narrow it down to a solution and if you get stuck with some specific create a new question.
Since version 5.0.0 of the Firebase JavaScript SDK, createUserWithEmailAndPassword() returns a Promise containing the new user's credentials as a UserCredentials object instead of a User object.
However, the UserCredentials object contains the User object as it's user property, which you can get the new email and user ID from as in #sketchthat's answer.
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(credential => {
// Save user here.
return firebase.database().ref('/users/' + credential.user.uid).set({
email: credential.user.email,
uid: credential.user.uid
});
})
.catch(function(error) {
// Handle Errors here.
});