Using firebase authentication and firestore to add user - javascript

Im trying to use user to the authentication of firebase and also firestore. Whhen I click on Save, the function SavePress is activated. The first time I click on this button, the user is added to firebase authentication but user is equal to null. Only at the second time it's work.
If anyone can help me..
Here is my code :
SavePress=async()=>{
if(this.state.email==="" || this.state.password==="" || this.state.firstname==="" || this.state.lastname==="" || this.state.confirmpassword==="" || (this.state.status===""))
{
alert("All fields are required")
}
else{
await firebase.auth().createUserWithEmailAndPassword(email,password)
.then(
firebase.auth().onAuthStateChanged(user=>
{
console.log("user : ",user)
if(user!=null)
{
firebase.firestore().collection("Users").doc(firebase.auth().currentUser.uid)
.set({firstname,lastname,email,status})
.then(this.checkStatus(status,{user}))
}
})
)
.catch((error)=>
{
console.log(error.code);//revoir cette erreur
if(error.code == "auth/email-already-in-use")
{alert("User already exists. Try to log in")}
})
}
}

Alternatively to Aymen's answer, you actually don't need an onAuthStateChanged in your then() callback. Since the then() callback is called when the user has been successfully created, you can simply do:
firebase.auth().createUserWithEmailAndPassword(email,password).then((credentials) => {
const user = credentials.user;
firebase.firestore().collection("Users").doc(firebase.auth().currentUser.uid)
.set({firstname,lastname,email,status})
.then(this.checkStatus(status,{user}))
).catch((error)=>{
console.log(error.code);//revoir cette erreur
if(error.code == "auth/email-already-in-use")
{alert("User already exists. Try to log in")}
})

when you sign to firebase, firebase auth take time to change auth, for this reason, you got a null in the first press. you need to use a listener for auth change.
firebase.auth().onAuthStateChanged(user => {
if(user){
// add user to firestore database.
}
})

Related

Firebase multifactor auth - Error object not returning resolver

I'm trying to add MFA inside my web app following the guide https://cloud.google.com/identity-platform/docs/web/mfa.
I started with enrolling the phone number successfully with the account and now when I want to "login" again using that phone number but I can’t use the number to get a code.
Check the code:
//I have imported my firebase services inside services/firebase.js
import { auth, signInWithEmailAndPassword, PhoneMultiFactorGenerator } from '#/services/firebase';
methods: {
//On login button click - this method is called
login: async function (event) {
var self = this;
await signInWithEmailAndPassword(auth, self.user_email, self.user_password)
.then(()=> {
...
//I am setting the user here, and giving access based on the role of the user
}
.catch((error) => {
console.log('Error:', error);
//Gives: Error: FirebaseError: Firebase: Error (auth/multi-factor-auth-required).
if (error.code == 'auth/multi-factor-auth-required') {
self.resolver = error.resolver;
//assigning to my data field so I can use this later with my phone number verification
console.log(error.resolver);
//UNDEFINED
...
} else {
...
}
});
}
}
In the code above the error object does not have a resolver, so "error.resolver" is undefined which I need in a later stage.
(FYI:- I am not using the Multi-Tenancy option)
UPDATE: Solved
The docs (https://cloud.google.com/identity-platform/docs/web/mfa) are outdated and functions are changed now.
Now the resolver doesn't come from the error object, we just need to call the resolver using a firebase function
getMultiFactorResolver
resolver = getMultiFactorResolver(auth, error);
Have a look here and you will undestand everything: https://firebase.google.com/docs/reference/js/auth.multifactorresolver#example_2

Firebase Auth: managing users with the Admin SDK

I have to write a firebase function that receives a JSON with a list of users and has to manage them with the following rules. For each user in the received list:
If the user is already registered (email/password) in firebase, I update it.
If the user is not registered yet, I create it
If a user is registered in firebase but it's not present in the received list, I disable it.
Now, I came up with the following solution: I iterate for each user in the received list. I call admin.auth().createUser() method so that if the user is not registered it will be created, otherwise the method throws an error and in the catch() block I call admin.auth().updateUser().
For the second part, I retrieve all the users registered with admin.auth().listUsers() and for each of them I check whether it's present in the received list: if don't so, I disable it.
For some reason, the correctness of this solution is uncertain: sometimes it doesn't work at all, other times when I call the function once it doesn't work but the second time a call the function it works, idk why is that.
This only happens when I send to the function a lot of users (about 400). If I send only few users it works fine.
Could anyone suggest to me maybe a better solution? Thanks a lot for your answer.
This is the function:
exports.addClients = functions.https.onRequest(async (req, res) => {
// fetch recevied list from payload
var receivedClients = req.body.clients;
// create or update user
receivedClients.forEach(client => {
admin.auth().createUser({
uid: client.id,
email: client.email,
emailVerified: true,
password: client.password,
})
.catch(err => {
// update user
admin.auth().updateUser(client.id, {
email: client.email
}).catch(err => {
// error updating user
log("Error updating user: " + err);
});
})
});
// disabling users not present in the received list
listUsers = await admin.auth().listUsers();
userRecords = listUsers.users;
userRecords.forEach(record => {
if (!receivedClients.some(client => client.id === record.uid)) {
// disable user
admin.auth().updateUser(record.uid, {
disabled: true
})
.catch(err => {
// error disabling user
log("Error disaling user: " + err);
});
}
});
// send response
res.sendStatus(200);
});

PreventDefault inside of promise in React

I'm new to full stack development and I was looking for some pointers to how I can handle errors that return from a promise.
Basically, I have Game IDs stored in a MongoDB collection. When a user enters a Game ID, I want to check if the Game ID exists in the collection. If it doesn't, I don't want to link the user to a new page. If it does, the user should go to a new page.
Currently, my code doesn't prevent default and the user still goes to the "waitpage", even if I use event.preventDefault. I'm wondering how I can stop the user from going to this page.
This is the code I have right now in the frontend.
const onJoinGame = (event) => {
event.persist()
axios.get(`${BACKENDLINK}/rooms/${gameId}/room_available`)
.then((res) => {
if(res.data.Status == true){
axios.put(`${BACKENDLINK}/rooms/${gameId}/add_user`,
{
username: username
})
}
})
.catch((error) => {
event.preventDefault()
setErrorGameId("That game doesn't exist!")
})
}
And in the return statement, I use this function like so.
<Link to={`/${gameId}/waitpage`} onClick={(event) => onJoinGame(event)}>
<button className = "submit" id="joinGame">Join Game</button>
</Link>
In the backend, this is what my get function returns.
const roomAvailable = (req, res) => {
Room.findOne({roomId: req.params.id}, (err, result) =>{
if(!result){
res.status(400).json('Error: ' + err)
}
else{
res.json({'Status': true})
}
})
}
Any help would be greatly appreciated!
You can't prevent the event from a promise, you'll need to do that synchronously in the event handler.
If you do need to navigate to the other page after all, you'll have to do that manually using the imperative API of the router package (which provides Link) you're using.

How to detect the user's firebase authentication login status in a vue js project?

I am trying to detect the userstate. If the user is logged in I want to set the data "userstate" to true. I am using vuefire and firebase into my vue project. I tried the way shown below, but it does not work
data() {
return {
userstate:false
};
},
watch:{
userstate:{
firebase.auth().onAuthStateChanged(function(user){
if(user){
this.userstate= true;}
else{
this.userstate=false;
}
})}
In Firebase you can check whether the user is signed in or not by using a function provided by the firebase which is auth().currentUser
// user will return true which means user EXISTS!
let user = firebase.auth().currentUser;
if (user) {
this.userstate = true; // If it exists
} else {
this.userstate = false; // If it doesn't
}
There are cases when the above mentioned method returns null / undefined for the user. So this solution is for your existing solution. So in that case try modifying your existing function to this:
async function IsLoggedIn() {
try {
await new Promise((resolve, reject) =>
firbase.auth().onAuthStateChanged(
user => {
if (user) {
// Yes User is signed in.
resolve('User is there');
} else {
// No user is not signed in.
reject('There is no user');
}
},
// Prevent console errors
error => reject(error)
)
)
return true
} catch (error) {
return false
}
}
Also since you intend to watch for the auth state change you can simply register the listener right after you initialize Firebase, you do not necessarily have to insert it in a VueJS watch block, you can insert it in your main.js for example, and if you are using a store like VueX you can update the state in the store and pull that information from any component of the VueX application.
firebase.initializeApp(configOptions);
firebase.auth().onAuthStateChanged(user => {
if (user) {
this.userstate = true;
} else {
this.userstate = false;
}
});

Trying to get the status of firebase user authentication

I have an authentication function using firebase which is just the auth code from the firebase documentation
export const signIn = (email,password) => {
firebase.auth().signInWithEmailAndPassword(email, password).then(()=>{
alert('Sign in Successful!')
}).catch(function(error) {
alert(error.message)
});
}
I call it like this
signIn(mail, password)
When I call it in my code, It works perfectly and the proper alerts appear. However, I want to actually receive something from my authentication function, like True or False if the user successfully logged in or not. Is there a way for me to receive this value from my function or any workarounds?
//evaluates to True if logged in successfully and vice versa
let authState = signIn(this.mail, this.password)
There's a couple approaches you could take with this, the first that comes to mind is the following:
export const signIn = (email, password) => {
return firebase.auth().signInWithEmailAndPassword(email, password).then(userCredential => {
alert('Sign in Successful!');
return true;
}).catch(error => {
alert(error.message);
return false;
});
}
// ......
let authState = await signIn(this.mail, this.password);
In promises you're able to return values from the .then() or .catch() method and then use that resolved value further in your code.
If you want to know when a user is signed in, no matter how they were signed in, you should instead use an auth state observer to set up a callback that will be invoked whenever the user becomes signed in or out, as shown in the documentation:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// User is signed out.
}
});

Categories

Resources