I have a react app with which I want to handle authentication with firebase.
My code successfully signs up and logs in but i am trying to add extra information on sign up but i have not been successful. I have tried answers [here]: Firebase v3 updateProfile Method and [here]: Firebase user.updateProfile({...}) not working in React App
But they don't seem to work. Below is my code
const SignUp = ({ history }) => {
const handleSignUp = useCallback(
async event => {
event.preventDefault();
const { email, password } = event.target.elements;
try {
let cred = await app
.auth()
.createUserWithEmailAndPassword(email.value, password.value);
await cred.user.updateProfile({
displayName: 'hello'
});
history.push('/');
} catch (error) {
console.log(error);
}
},
[history]
);
Please how do i fix this because currently on the email and username sets? Thanks
In order to change user profile you should use firebase.auth().onAuthStateChanged() function, as follows:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
} else {
// No user is signed in.
}
});
Then you can get others user properties. Here you can find all info you need. https://firebase.google.com/docs/auth/web/manage-users. Hope it helps.
Related
So ,I am an newbie in firebase and working on an team project. What client wants us to do is make user login with phonenumber and otp.
First, I managed to login the user using this code as follows
import React, { useState } from "react";
import { RecaptchaVerifier, signInWithPhoneNumber } from "firebase/auth";
import { auth } from "../../firebase/config";
const SignInWithNumber = () => {
const [phone, setphone] = useState();
const [otp, setotp] = useState();
const handleRecaptcha = () => {
window.recaptchaVerifier = new RecaptchaVerifier(
"sign-in-button",
{
size: "invisible",
callback: (response) => {
// reCAPTCHA solved, allow signInWithPhoneNumber.
},
},
auth
);
};
const handleSubmitNumber = (e) => {
e.preventDefault();
if (phone >= 10) {
console.log(phone);
handleRecaptcha();
const phoneNumber = "+91" + phone;
const appVerifier = window.recaptchaVerifier;
signInWithPhoneNumber(auth, phoneNumber, appVerifier)
.then((confirmationResult) => {
window.confirmationResult = confirmationResult;
// ...
console.log("otp sent");
})
.catch((error) => {
// Error; SMS not sent
// ...
console.log(error + "SMS not sent");
});
}
};
const handleSubmitOtp = (e) => {
e.preventDefault();
const code = otp;
const x = window.confirmationResult;
x.confirm(code)
.then((result) => {
// User signed in successfully.
const user = result.user;
console.log(user);
// ...
})
.catch((error) => {
// User couldn't sign in (bad verification code?)
// ...
console.log(error);
});
};
const handleChange = (e) => {
e.preventDefault();
const { name, value } = e.target;
switch (name) {
case "phone":
setphone(value);
break;
case "otp":
setotp(value);
break;
default:
break;
}
};
return (
<div>
<h2>LogIn</h2>
<form onSubmit={handleSubmitNumber}>
<div id="sign-in-button"></div>
<input type="number" name="phone" required onChange={handleChange} />
<button type="submit">Submit</button>
</form>
<h2>Submit OTP</h2>
<form onSubmit={handleSubmitOtp}>
<input type="number" name="otp" required onChange={handleChange} />
<button type="submit">Submit</button>
</form>
</div>
);
};
export default SignInWithNumber;
Now , I am able to login user and get its uid in console but I also want to signup/register the user with his phone number +otp and get his credentials such as name , address etc.
This may be a dumb question but I cant find any solution to this.
Thanks in advance :)
There isn't any sign up method when using phone based auth. If a user doesn't exists then the account will be created (technically a sign up) else user will be logged in to existing account.
You can however check the isNewUser property after authentication to check if user logged in for first time or no.
Checkout Check for isNewUser with Firebase email link auth using modular JS SDK
x.confirm(code)
.then((result) => {
// User signed in successfully.
const { isNewUser } = getAdditionalUserInfo(result)
if (isNewUser) {
// New user - sign up
} else {
// Existing user - log in
}
})
First, the question is not dumb.
Secondly, for a solution, after signing in with phone number successfully, given that the account was just created (a new user), you can now show a form to obtain the user's name and other details.
On submit of this form, save the name to firebase authentication user object with updateProfile. Then save other data to a Firestore document with the user's uid as document id and preferably on the users collection.
On page load, you can check if the user is signed in, if true, check if the user has data in Firestore, if false, show the user the above form, else, continue app usage as you want.
I want to add the username on the signup of the user and I am using the following code:
//Create Account With Email&Password
const createUser = (email, password, username) => {
return createUserWithEmailAndPassword(auth, email, password).then(() => {
updateProfile(auth.currentUser, {
displayName: username,
});
});
};
This is my useEffect in the same js file
useEffect(() => {
console.log('useEffect');
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
});
return () => unsubscribe();
}, []);
This code is adding the displayname successfully, but when I redirect to my account page the displayname is not directly showing up and I am getting a memory leak warning from the router-dom. Is there a cleaner and better way to do this?
I believe it's because the account page loads before firebase loads the auth data, you can use something like
onAuthStateChanged(auth,(user)=>{
if(user){
getUserName = auth.currentUser.displayName;
// Load the rest of the page
}
}
at your redirected user page,assuming you are using the right auth state, which you can refer from here https://firebase.google.com/docs/auth/web/auth-state-persistence?authuser=0
I'm new to react and firebase and was trying to create a firestore document only during the creation of user.
Its working fine on the local provider as there sign in and sign up are two different things but when it comes to google o Auth both the options use same function.
So how do i create my initial documnet during creation of user via google o Auth as it just resets my entire document when i log out and log in back.
googleAuth function
function googleAuth(provider) {
return firebase
.auth()
.signInWithPopup(provider)
.then(async function createUserDb(userCredentials) {
await setDoc(doc(db, "users", userCredentials.user.uid), {myList: []},{ merge: true })
})
}
sign up and sign in functions
function signUp(email, password) {
return auth.createUserWithEmailAndPassword(email, password).then(
async function createUserDb(userCredentials) {
console.log(userCredentials.user.uid);
await setDoc(doc(db, "users", userCredentials.user.uid), {myList: []})
})
}
function signIn(email, password) {
return auth.signInWithEmailAndPassword(email, password)
}
my firestore users collection when a new user is created (google auth user here)
it should save the data even after sign in (local auth user here)
after scraping through some posts found .additionalUserInfo.isNewUser method which checks if the user has created new account or is already a user which fixed my issue.
Thank you for any help that you guys provided.
function googleAuth(provider) {
return firebase
.auth()
.signInWithPopup(provider)
.then(async function createUserDb(userCredentials) {
if(userCredentials.additionalUserInfo.isNewUser) {
await setDoc(doc(db, "users", userCredentials.user.uid), {myList: []},{ merge: true })
}
})
}
I was developing an app which I like implements Firebase as Authenticating system.
My problem comes when I try to set up the Authentication with Google provider when I try to modify the colletion of firestore where the users are saved. My code is the following:
export const loginWithGoogle = () => {
const navigation = useNavigation();
useEffect(() => {
setTimeout(() => {
navigation.navigate('/RegisterScreen');
}, 10000);
}, []);
return () => {
return firebase
.auth()
.signInWithPopup(Providers.google)
.then(async result => {
//console.log(result.credential.accessToken);
const user = result.user;
console.log(user);
//This 2 lines below doesn't work to get the colletion.
db.('users').setItem('userid', user!.uid);
collection.(db,'users').setItem('photoURL', user!.photoURL);
//TODO if userid exists IN USERS db then use update IF NULL use set
await db.collection('users').doc(user!.uid).update({
// id: user.uid,
name: user!.displayName,
email: user!.email,
phone: user!.phoneNumber,
photoURL: user!.photoURL,
});
})
.then(() => {
navigation.navigate('ProtectedScreen');
})
.catch(err => {
console.log(err);
});
};
};
So I guess that my error comes from unknowledge of how to manage data saved on firestore.
If you can help take thanks in advance !
There are some thing we need to clear here:
You can just merge the data. There is no need to read/get it from Firestore to check if it is there and save it onyl if it's not. You will be charged for reads and writes. In the end it's cheaper to always just write without checking if something exists.
Also this code here:
db.('users').setItem('userid', user!.uid);
collection.(db,'users').setItem('photoURL', user!.photoURL);
especially with the db.( and collection.( doens't look good. Even if it is it's not for getting data but for saving it.
Could you pls clarify witch Firebase SDK you use: version 8 or 9. Also pls check a little bit the docs here.
I'll appreciate assistance with how to reauthenticate a user in Firebase. I wonder if it makes any sense adding all these great features if the documentation doesn't explain how to use it:
Currently, this is what I'm trying, and it ain't working. Errors as cannot read property 'credential' of undefined
In constructor:
constructor(#Inject(FirebaseApp) firebaseApp: any) {
this.auth = firebaseApp.auth();
console.log(this.auth);
}
then the function
changePassword(passwordData) {
if(passwordData.valid) {
console.log(passwordData.value);
// let us reauthenticate first irrespective of how long
// user's been logged in!
const user = this.auth.currentUser;
const credential = this.auth.EmailAuthProvider.credential(user.email, passwordData.value.oldpassword);
console.log(credential);
this.auth.reauthenticate(credential)
.then((_) => {
console.log('User reauthenticated');
this.auth.updatePassword(passwordData.value.newpassword)
.then((_) => {
console.log('Password changed');
})
.catch((error) => {
console.log(error);
})
})
.catch((error) => {
console.log(error);
})
}
}
The reauthenticate() method is called on a firebase.User, not on firebase.auth.Auth itself.
var user = firebase.app.auth().currentUser;
var credentials = firebase.auth.EmailAuthProvider.credential('puf#firebaseui.com', 'firebase');
user.reauthenticate(credentials);
Update (July 2017):
There are some breaking change in the 4.0 version of the Firebase Web SDK. From the release notes:
BREAKING: firebase.User.prototype.reauthenticate has been removed in favor of firebase.User.prototype.reauthenticateWithCredential.
As far as I can tell the reauthenticateWithCredentialis a drop-in replacement for the old method.
Here's some code that enabled users to (a) reauthenticate in Firebase and (b) change their passwords after reauthenticating for me. I researched for about an hour while writing this, so hopefully it saves someone a minute.
Wrote in VueJS:
changePassword() {
let self = this; // i use "self" to get around scope issues
var user = firebase.auth().currentUser;
var credential = firebase.auth.EmailAuthProvider.credential(
this.$store.state.userId, // references the user's email address
this.oldPassword
);
user.reauthenticateWithCredential(credential)
.then(function() {
// User re-authenticated.
user.updatePassword(self.newPassword)
.then(function() {
console.log("Password update successful!");
})
.catch(function(error) {
console.log(
"An error occurred while changing the password:",
error
);
});
})
.catch(function(error) {
console.log("Some kinda bug: ", error);
// An error happened.
});
Slight changes as of May 2019, see more details here. Code is as follows:
var user = firebase.auth().currentUser;
var credential = firebase.auth.EmailAuthProvider.credential(user.email, password);
// Prompt the user to re-provide their sign-in credentials
return user.reauthenticateWithCredential(credential);
Call changeEmail("new email","password") in onPressed directly to update the user email with no reauthentication required error
RaisedButton(
onPressed: () {
changeEmail(_emailController.text, _passwordController.text);
}
Future<void> changeEmail(String email, String password) async {
User user = await FirebaseAuth.instance.currentUser;
print(email);
print(password);
try {
try {
var authResult = await user.reauthenticateWithCredential(
EmailAuthProvider.getCredential(
email: user.email,
password: password,
),
);
user.updateEmail(email).then((_) {
print("Succesfull changed email");
_backthrow();
}).catchError((error) {
showAlertDialog(context, error.message);
print("email can't be changed" + error.toString());
});
return null;
} catch (e) {
print("2");
}
} catch (e) {
print(e.message);
showAlertDialog(context, e.message);
}
}
Hers a full example how to reauthenticate with Firebase
var pass = "abcdefg";
var user = firebase.auth().currentUser;
var credential = firebase.auth.EmailAuthProvider.credential(user.email, pass);
user.reauthenticateWithCredential(credential).then(() => {
console.log("Its good!");
}).catch((error) => {
console.log(error);
});
Since 2021: If you use Firebase JS API 9.x (the tree shakable version) this is the most recent way:
https://cloud.google.com/identity-platform/docs/web/reauth
With credentials
import { getAuth, reauthenticateWithCredential } from "firebase/auth";
const auth = getAuth();
const user = auth.currentUser;
// todo for you: prompt the user to re-provide their sign-in credentials
const credential = promptForCredentials();
reauthenticateWithCredential(user, credential).then(() => {
// ...
}).catch((error) => {
// ...
});
With popup
import { getAuth, reauthenticateWithPopup, OAuthProvider } from "firebase/auth";
const auth = getAuth();
// todo for you: change to appropriate provider
const provider = new OAuthProvider('apple.com');
reauthenticateWithPopup(auth.currentUser, provider)
.then((result) => {
// ...
})
.catch((error) => {
// ...
});
This is how I re-authenticate a user in Firebase:
import { getAuth, EmailAuthProvider, reauthenticateWithCredential } from "firebase/auth";
const auth = getAuth()
const reauthenticateUser = async (email, password) => {
const user = auth.currentUser;
try {
const credential = EmailAuthProvider.credential(email, password);
await reauthenticateWithCredential(user, credential)
} catch (error) {
Alert.alert("Error", "The email or password is incorrect. Please try again.")
}
}
I was getting that re-authentication error auth/requires-recent-login when saving the primary email.
I couldn't figure out how to implement that poorly documented reauthenticateWithCredential(credential) method, so, I simply logged-out the user and redirected to login page. It's a hack but It works like charm!
firebase.auth().signOut();