I am trying to change/update a user's email address using :
firebase.auth().changeEmail({oldEmail, newEmail, password}, cb)
But I am getting ...changeEmail is not a function error. I found the reference here from the old firebase docu.
So how to I do it in the 3.x version? Because I cant find a reference in the new documentation.
You're looking for the updateEmail() method on the firebase.User object: https://firebase.google.com/docs/reference/js/firebase.User#updateEmail
Since this is on the user object, your user will already have to be signed in. Hence it only requires the password.
Simple usage:
firebase.auth()
.signInWithEmailAndPassword('you#domain.example', 'correcthorsebatterystaple')
.then(function(userCredential) {
userCredential.user.updateEmail('newyou#domain.example')
})
If someone is looking for updating a user's email via Firebase Admin, it's documented over here and can be performed with:
admin.auth().updateUser(uid, {
email: "modifiedUser#example.com"
});
FOR FIREBASE V9 (modular) USERS:
The accepted answer will not apply to you. Instead, you can do this, i.e., import { updateEmail } and use it like any other import. The following code was copy/pasted directly from the fb docs at https://firebase.google.com/docs/auth/web/manage-users
Happy coding!
import { getAuth, updateEmail } from "firebase/auth";
const auth = getAuth();
updateEmail(auth.currentUser, "user#example.com").then(() => {
// Email updated!
// ...
}).catch((error) => {
// An error occurred
// ...
});
You can do this directly with AngularFire2, you just need to add "currentUser" to your path.
this.af.auth.currentUser.updateEmail(email)
.then(() => {
...
});
You will also need to reauthenticate the login prior to calling this as Firebase requires a fresh authentication to perform certain account functions such as deleting the account, changing the email or the password.
For the project I just implemented this on, I just included the login as part of the change password/email forms and then called "signInWithEmailAndPassword" just prior to the "updateEmail" call.
To update the password just do the following:
this.af.auth.currentUser.updatePassword(password)
.then(() => {
...
});
updateEmail needs to happen right after sign in due to email being a security sensitive info
Example for Kotlin
// need to sign user in immediately before updating the email
auth.signInWithEmailAndPassword("currentEmail","currentPassword")
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success now update email
auth.currentUser!!.updateEmail(newEmail)
.addOnCompleteListener{ task ->
if (task.isSuccessful) {
// email update completed
}else{
// email update failed
}
}
} else {
// sign in failed
}
}
async updateEmail() {
const auth = firebase.auth();
try {
const usercred = await auth.currentUser.updateEmail(this.email.value);
console.log('Email updated!!')
} catch(err) {
console.log(err)
}
}
You can use this to update email with Firebase.
Firebase v9:
const changeEmail = (userInput) => {
const { newEmail, pass } = userInput
signInWithEmailAndPassword(auth, oldEmail, pass)
.then(cred => updateEmail(cred.user, newEmail))
}
Related
I currently have a file for authentication called AuthContext.js and a seperate file called Login.js for my login page. Firebase is only imported into the AuthContext file and it currently works, the method appears as follows
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password);
}
And the method is called in the Login file inside of an async function.
async function handleSubmit(e) {
e.preventDefault();
if (passwordRef.current.value !== passwordConfirmRef.current.value) {
return setError("Passwords do not match");
}
try {
setError("");
setLoading(true);
await signup(emailRef.current.value, passwordRef.current.value);
navigate("/");
} catch (err) {
setError("Failed to create an account");
}
setLoading(false);
}
I am now attempting to integrate email authentication into the function. I would like to get it to where, if an account remains unverified for a elongated duration then it will delete the account, but I think that Is likely in the Firebase settings.
I found this article on geeksforgeeks that suggested calling the method in the following manner:
const signup = ()=>{
auth.createUserWithEmailAndPassword(email , password)
.then((userCredential)=>{
// send verification mail.
userCredential.user.sendEmailVerification();
auth.signOut();
alert("Email sent");
})
.catch(alert);
}
However, when I attempted to return this function in the form
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password).then(
(userCredentials) => {
userCredentials.user.sendEmailVerification();
auth.signOut();
auth.alert("Please verify your email address before logging in.");
}
);
}
It does not work properly, and I get error messages every time I try to sign up a new account. How do I properly implement this to where the promise returns properly and displays the correct message? Is there a way for me to link them to the /login page with an alert already on it that says "Please verify your email address before logging in."? Thanks in advance for any help!
I am implementing a cloud function for updating the current user's password.
Basically, the logic I want to follow is:
(Client side)
0. Complete form and submit the data (current password and new password).
(Backend)
1. Get the current user email from the callable function context.
2. Re-authenticate the current user using the provided current password.
2.1. If success, change the password and send a notification email.
2.2. Else, throw an error.
Here is my current code:
const { auth, functions } = require("../../services/firebase");
...
exports.updatePassword = functions
.region("us-central1")
.runWith({ memory: "1GB", timeoutSeconds: 120 })
.https.onCall(async (data, context) => {
const { currentPassowrd, newPassword } = data;
const { email, uid: userId } = context.auth.token;
if (!userId) {
// throw ...
}
try {
//
// Problem: `firebase-admin` authentication doesn't include
// the `signInWithEmailAndPassword()` method...
//
await auth.signInWithEmailAndPassword(email, currentPassowrd);
await auth.updateUser(userId, {
password: newPassword,
});
sendPasswordUpdateEmail(email);
} catch (err) {
// ...
throw AuthErrors.cannotUpdatePassword();
}
});
My problem is that the firebase-admin package doesn't include the signInWithEmailAndPassword, and I need a way to handle this, to check that "currentPassword" is correct, inside my function.
My other option, if the one I have described is not possible, is to update the password using the firebase sdk in the client side, and then to call a firebase function to send the notification email.
Strictly speaking you don't need to re-authenticate the user in the Cloud Function: If you get a value for context.auth.uid in your Callable Cloud Function, it means that the user is authenticated in the front-end and you can therefore safely call the updateUser() method.
If you want to deal with the case when the user left his device opened, and someone updates his password, as explained in the comments under your question, I would suggest you use the reauthenticateWithCredential() method in the front-end, which re-authenticates a user using a fresh credential.
Do as follows:
import {
EmailAuthProvider,
getAuth,
reauthenticateWithCredential,
} from 'firebase/auth'
const email = auth.currentUser.email;
// Capture the password value
// e.g. via a pop-up window
const password = ...;
const auth = getAuth();
const credential = EmailAuthProvider.credential(
email,
password
);
await reauthenticateWithCredential(
auth.currentUser,
credential
);
// If no error is thrown, you can call the Callable Cloud Function, knowing the user has just re-signed-in.
I am working for a task related to react native app based user management. After they successful sign up themselves as a user, I include a data which is store Boolean value and I have named it as emailVerifiedAccount (this is the stored data if they registered themselves successful and indicate if they are a verified user if they click on email verification link send to them). In login screen I would like to check the Boolean value that I get from firestore in onAuthStateChanged and only direct them to index screen when the emailVerifiedAccount that I get is return true. Code below is authstatechanged for login screen .
const onAuthStateChanged = (user) => {
if (user) {
checkEmailVerifiedAccount=firestoreService.isEmailVerifiedAccount(user);
try {
if(checkEmailVerifiedAccount===true){
navigation.navigate('Index');
}else{
Alert.alert(
"Verify as a Playbookx user",
"Please click on email verification link send to your email. If you do not receive any email ,please contact user support",
"You may come back to login again after you verified your email",
[
{ text: "OK"}
]
)
}
} catch (error) {
console.log(error);
}
}
};
and in firestore.js is where all the code and function that is related with Firestore database. isEmailVerifiedAccount is one of the class object which checking verified user using email.
isEmailVerifiedAccount = async (user) => {
return await firestore()
.collection('users')
.doc(user)
.get()
.then(snapshot => {
if (snapshot.exists){
const user=snapshot.data();
const emailVerifiedAccount={
emailVerifiedAccount:user.emailVerifiedAccount
};
return emailVerifiedAccount
}
})
.catch(error => {
console.log(error);
});
};
And the problem that I facing right now is that, it lead me to index screen when the emailVerifiedAccount in Firestore is false. Picture below is the structure for Firestore.
Your isEmailVerifiedAccount function is asynchronous, so when calling it you have to await the result:
checkEmailVerifiedAccount = await firestoreService.isEmailVerifiedAccount(user);
const checkEmailVerifiedAccount = firestoreService.isEmailVerifiedAccount(user);
checkEmailVerifiedAcccount seems to be an object but you are checking if it's equal to true. Either return user.emailVerifiedAccount directly from isEmailVerifiedAccount function or read that property like this:
const checkEmailVerifiedAccount = firestoreService.isEmailVerifiedAccount(user);
if(checkEmailVerifiedAccount.emailVerifiedAccount) {
navigation.navigate('Index');
}
am working on a little project and i did finish all the authentication work but one thing,am wondering how to check if the email is real before going into the process of signup,
by the way am using react and Firebase and i did look online and i did find a package called email-existence i did try it and it dose return true if the email is real and false if the email dosent exist but thats not working when i use it with react it return an error
import firebase from '../util/firebase';
const emailExistence = require('email-existence');
export const normalSignup = (props, setSign, email, password, confirmPassword, username) => {
emailExistence.check(email, function (error, response) { // return error here addresses.sort is not a function
console.log('res: ' + response);
});
}
anyway am wondering if there's a way to do it with Firebase without external packages thanx in advance
PS:am not using cloud functions
Well assuming you want to check if the email is a verified email address you can write the code in the following way
import firebase from '../util/firebase';
const App = {
firebase: firebase,
getLoggedInUser: () => {
const currentUser = App.firebase.auth().currentUser
if (currentUser) {
return {
email: currentUser.email,
userId: currentUser.uid,
isEmailVerified: currentUser.emailVerified
}
} else {
return undefined
}
},
isAuthenticated: () => {
return (App.getLoggedInUser() && App.getLoggedInUser().isEmailVerified)
},
authenticate: async (email, password) => {
await App.firebase.auth().signInWithEmailAndPassword(email, password)
},
signup: async (email, password) => {
const userCredential = await App.firebase.auth().createUserWithEmailAndPassword(email, password)
await userCredential.user.sendEmailVerification()
return `Check your email for verification mail before logging in`
},
Here the following happens
When a user signs up the signup method is called and an email verification is sent by firebase as shown in the above code
When a user logs in the authenticate method is called so according to firebase you are logged in
However to redirect or render a certain page say after log in you can use the isAuthenticated method to display a page to a certain user
So you can pass method isAuthenticated as a prop to react-router and render your web application how you want.
This way only real and authentic email id which are verified will have access to your app
Note
This method is working already in prod but its using VueJS and is an opensource project on github let me know if you want to reference it
Maybe just use a regex to check if the email is valid?
According to this webpage for JavaScript you just need:
const emailRegex = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (emailRegex.test(email)) {
console.log('Email valid!');
}
This won't stop people entering emails for incorrect domains, but ensures that if someone uses a mail server that isn't widely known, it will get accepted too.
Your only option on the client side (if you are on Firebase I suppose you don't have the luxury to run a Node backend) to fetch a similar service as email-existence which returns a "valid" or "invalid" response if you GET the endpoint with the email address.
These are usually premium services, but if you have low traffic you can try out a free one. In my example it is Mailboxlayer.
Their endpoint can be called like this (and of course if you are stick to the client side it means anyone can steal your api key from production via browser network tab!):
GET http://apilayer.net/api/check?access_key=YOUR_ACCESS_KEY&email=richard#example.com
Which returns a JSON:
{
"email": "richard#example.com",
"did_you_mean": "",
"user": "support",
"domain": "apilayer.net",
"format_valid": true,
"mx_found": true,
"smtp_check": true,
"catch_all": false,
"role": true,
"disposable": false,
"free": false,
"score": 0.8
}
Best to use score, which:
[...] returns a numeric score between 0 and 1 reflecting the quality and deliverability of the requested email address.
In React:
const [data, setData] = useState(null)
const [emailToVerify, setEmailToVerify] = useState('richard#example.com') // just for the sake of example
const apiKey = process.env.API_KEY
const fetchEmailVerificationApi = useCallback(async () => {
try {
const response = await fetch(`http://apilayer.net/api/check?access_key=${apiKey}&email=${emailToVerify}`)
const json = await response.json()
setData(json.score) // returns a numeric score between 0 and 1 reflecting the quality and deliverability of the requested email address.
} catch (e) {
console.error(e)
}
}, [apiKey, emailToVerify])
useEffect(() => {
fetchEmailVerificationApi()
}, [fetchEmailVerificationApi])
I am developing an app in React Native and I want to implement logging in with Facebook.
I have an API in Node.js where I handle the logic for users to log in, etc.
I use passport.js to let users log in with either Facebook or traditional Email.
I am opening an URL in my API with SafariView which is just a regular "WebView" directly in my app.
I have tried using the following code:
class FacebookButton extends Component {
componentDidMount() {
// Add event listener to handle OAuthLogin:// URLs
Linking.addEventListener('url', this.handleOpenURL);
// Launched from an external URL
Linking.getInitialURL().then((url) => {
if (url) {
this.handleOpenURL({ url });
}
});
}
componentWillUnmount() {
Linking.removeEventListener('url', this.handleOpenURL);
}
handleOpenURL({ url }) {
// Extract stringified user string out of the URL
const [, user_string] = url.match(/user=([^#]+)/);
this.setState({
// Decode the user string and parse it into JSON
user: JSON.parse(decodeURI(user_string))
});
if (Platform.OS === 'ios') {
SafariView.dismiss();
}
}
openURL(url) {
if (Platform.OS === 'ios') {
SafariView.show({
url: url,
fromBottom: true,
});
} else {
Linking.openURL(url);
}
}
render() {
return (
<Button
onPress={() => this.openURL('https://mywebsite.com/api/auth/facebook')}
title='Continue with Facebook'
...
so I guess I will have to do the authentication on URL https://mywebsite.com/api/auth/facebook and then send the user to an url that looks something like OAuthLogin://..., but I am not entirely sure how to use it.
Can anyone help me move in the right direction?
import { LoginManager, AccessToken } from 'react-native-fbsdk'; // add this file using npm i react-native-fbsdk
Create function
const onFacebookButtonPress = async () => {
// Attempt login with permissions
const result = await LoginManager.logInWithPermissions(['public_profile', 'email']);
if (result.isCancelled) {
throw 'User cancelled the login process';
}
// Once signed in, get the users AccesToken
const userInfo = await AccessToken.getCurrentAccessToken();
if (!userInfo) {
throw 'Something went wrong obtaining access token';
}
console.log('user info login', userInfo)
// Create a Firebase credential with the AccessToken
const facebookCredential = auth.FacebookAuthProvider.credential(userInfo.accessToken);
setGoogleToken(userInfo.accessToken)
// Sign-in the user with the credential
return auth().signInWithCredential(facebookCredential)
.then(() => {
//Once the user creation has happened successfully, we can add the currentUser into firestore
//with the appropriate details.
console.log('current User ####', auth().currentUser);
var name = auth().currentUser.displayName
var mSplit = name.split(' ');
console.log("mSplit ",mSplit);
let mUserDataFacebook = {
user_registration_email: auth().currentUser.email,
user_registration_first_name: mSplit[0],
user_registration_last_name: mSplit[1],
registration_type: 'facebook',
user_registration_role: "Transporter",
token: userInfo.accessToken,
user_image : auth().currentUser.photoURL,
};
console.log('mUserDataFacebook',mUserDataFacebook)
LoginWithGoogleFacebook(mUserDataFacebook) /// Call here your API
firestore().collection('users').doc(auth().currentUser.uid) //// here you can add facebook login details to your firebase authentication.
.set({
fname: mSplit[0],
lname: mSplit[1],
email: auth().currentUser.email,
createdAt: firestore.Timestamp.fromDate(new Date()),
userImg: auth().currentUser.photoURL,
})
//ensure we catch any errors at this stage to advise us if something does go wrong
.catch(error => {
console.log('Something went wrong with added user to firestore: ', error);
})
})
}
Call this function on button press onFacebookButtonPress()
For android need to setup and add facebook id in
android/app/src/main/res/values/strings.xml file
add these two lines.
YOUR_FACEBOOK_ID
fbYOUR_FACEBOOK_ID //Don't remove fb in this string value
/////////////add this code in AndroidMainfest.xml file
//////////This code add in MainApplication.java file
import com.facebook.FacebookSdk;
import com.facebook.appevents.AppEventsLogger;
/////////add code build.gradle file
implementation 'com.facebook.android:facebook-android-sdk:[5,6)'