How do we do this now:
const auth = getAuth(firebaseApp);
export async function updateUserEmail(email) {
try {
// let updatedUser = if need access
await auth.currentUser.updateEmail(email);
} catch (e) {
alert(e.message);
throw new Error();
}
}
updateEmail is no longer a method
You need to import updateEmail from the SDK this way now:
import firebase from "firebase/compat/app";
import { getAuth, onAuthStateChanged, updateEmail } from "firebase/auth";
// Initialize Firebase App
const app = firebase.initializeApp(firebaseConfig);
const auth = getAuth(app);
onAuthStateChanged(auth, (user) => {
console.log("Old Email", user.email);
updateEmail(user, "new#email.tld").then(() => {
console.log("email updated");
}).catch((e) => {
console.log(e);
});
});
Also you need to pass the user object itself in the updateEmail function so for testing purpose I've added the code in onAuthStateChanged but you can fetch the object or actually store it when page loads.
Related
update 2, i logged the errors
update: I changed const db = getDatabase to const db getDatabase()
it printed to the console that the credentials were removed, but when i checked database, they still remain.
plus this error
I am trying to delete the user data as well as the authenticated data. I am successfully deleting the authenticated data, but it leaves the rest of the data in the database untouched. I have tried the following code:
import React from "react";
import { getAuth, deleteUser, onAuthStateChanged } from "firebase/auth";
import { remove, ref, getDatabase } from "firebase/database";
import { connectStorageEmulator } from "firebase/storage";
function DeleteUser() {
const auth = getAuth();
const user = auth.currentUser;
const db = getDatabase;
const del = ()=>{
if (user) {
remove(ref(db,'users'+user.uid))
.then(()=>{
console.log("credentials emoved")
})
.catch((error)=>{
console.log('failed')
});
deleteUser(user)
.then(() => {
console.log("User deleted");
})
.catch((error) => {
console.log("failed");
});
} else {
console.log("user is sighned out");
}
}
return (
<div>
<button onClick={del}>Delete</button>
</div>
);
}
export default DeleteUser;
I am using this bit to try removing the data, but I am getting some errors
remove(ref(db,'users'+user.uid))
.then(()=>{
console.log("credentials emoved")
})
.catch((error)=>{
console.log('failed')
});
The getDatabase() is a function but you are just assigning that to a variable instead of calling it.
const db = getDatabase;
// change that to
const db = getDatabase();
The recent login required essentially means user must have logged in (by entering their password, signing in by Google, etc) recently. If they have been logged in for a while then you'll need to reauthenticate the user (ask them to enter their password if using Email-password auth).
Checkout Firebase: recent login requested for more information.
I'm trying to sign up a new user with email and password using Firebase.
Below you can see my Vue method.
signup() {
if (!this.validate()) return
const auth = getAuth()
createUserWithEmailAndPassword(auth, this.email, this.password)
.then(() => {
console.log("Signup successful!")
})
.catch((error) => {
const errorMessage = error.message
console.error("Signup error! ", errorMessage)
})
}
Right below my script tag I have this import:
import { getAuth, createUserWithEmailAndPassword } from "#/firebase.js"
And in my firebase.js file I have this code:
import { initializeApp } from "firebase/app"
import { getAuth, createUserWithEmailAndPassword } from "firebase/auth"
const firebaseConfig = {
// here I pasted the config object I got from Firebase
}
initializeApp(firebaseConfig)
export { getAuth, createUserWithEmailAndPassword }
When I try to sign a new user up, I get this printed out in the console:
POST https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=AIzaSyDmpWucdj9MuwM5mvjA5_TKMCFlsUXUGpg 400
Signup successful!
I can see that I have a new user registered in my Firebase console. Why is this error showing up then?
I am importing 'firebaseApp' from a file where I have done all the setup of firebase and I have implemented email, google and Facebook authentication but when I am implementing the phone number auth the ReCaptcha is not a constructor I am using ReactJs functional component.
Is there any way of implementing phone number auth without ReCaptcha or if not how can I fix the error.
Setup of firebase
import firebase from 'firebase/app';
import 'firebase/auth'
import 'firebase/firestore';
// Web app's Firebase configuration
var firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
};
// Initialize Firebase
export const firebaseApp = firebase.initializeApp(firebaseConfig);
export const auth = firebase.auth();
export const db = firebase.firestore();
export const google_provider = new firebase.auth.GoogleAuthProvider();
export const facebook_provider = new firebase.auth.FacebookAuthProvider();
This is the place I am taking the number as user input and sending the OTP for verification but the sample code number is hardcoded.
import { firebaseApp, auth } from '../../../firebase/firebasesetup'
function Form() {
const setuprecaptcha = () => {
window.recaptchaVerifier = new firebaseApp.auth.RecaptchaVerifier('recaptcha-container',
{
'size': 'invisible',
'callback': function (response) {
console.log("captcha resolved");
// sendsms();
}
});
}
const sendsms = () => {
setuprecaptcha();
var phoneNumber = '+918220310506';
var appVerifier = window.recaptchaVerifier;
auth.signInWithPhoneNumber(phoneNumber, appVerifier)
.then(function (confirmationResult) {
window.confirmationResult = confirmationResult;
}).catch(function (error) {
alert("not sent")
});
}
return (
<input type="text" placeholder="Mobile" value={mob}
onChange={e => setMob(e.target.value)} />
<div id="recaptcha-container"></div>
<button onClick={sendsms} id='sign-in-button'>Send otp</button>
)
}
export default Form
Ok, so I am answering My own question. This kind of looks Weird but still if anyone of you faces the same problem as mine.
2 things I need to solve in the firebase_setup file and add the main function in React functional component. (Total 3 updates)
firebase_setup file
first
import firebase from 'firebase'; and not import firebase from 'firebase/app';
second
firebase.initializeApp(firebaseConfig); export const firebaseApp = firebase
React functional component
import { firebaseApp} from './firebase_setup';
const sendsms = () => {
//If you want to make the recaptcha invisible
var recaptcha = new firebaseApp.auth.RecaptchaVerifier('recaptcha-container', {
'size': 'invisible'
});
//If you want to make the recaptcha visible
var recaptcha = new firebaseApp.auth.RecaptchaVerifier('recaptcha-container');
//Your phone number with the country code
var number = '+**********';
//actual code begins here
auth.signInWithPhoneNumber(number, recaptcha).then(function (e) {
var code = prompt("enter the code sent to your mobile number");
if (code === null) return;
e.confirm(code).then(function (result) {
alert(result.user + ' verified ')
}).catch(function (error) {
alert('Could not verify,Please try again');
});
}).catch(function (error) {
alert('Please try again.We were unable to reach your phone.Select the correct code and the phone number');
});
}
Method reauthenticateAndRetrieveDataWithCredential requires credential.
I tried this and it gives me an error:
const user = firebase.auth().currentUser;
const credential = firebase.auth.OAuthCredential;
await user.reauthenticateAndRetrieveDataWithCredential(credential);
await user.updateEmail(email);
return email;
Error message
reauthenticateAndRetrieveDataWithCredential failed: First argument "credential" must be a valid credential.
I only have oath authentication (no email + password). So I can't figure out what credential firebase need. Any help?
Edit:
For some reason my firebase.auth.OAuthCredential or (firebase.auth.AuthCredential) return undefined. User is signedIn/authed.
Ran into this issue in a Vue.js project where we have a firebase.js file that handles module imports and exports of const.
Hoping this will help someone save time when using a similar setup.
File: firebase.js
import firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/database'
// Initialize Firebase
const app = firebase.initializeApp(options)
export const fb = firebase
export const auth = app.auth()
export const db = app.database()
export const functions = app.functions()
Example of changePassword() in other script file or inside *.vue
import { fb, auth } from './firebase.js'
...
changePassword() {
if (yourFormValidation == true) {
let user = auth.currentUser
const credentials = fb.auth.EmailAuthProvider.credential(
user.email,
this.current_password
)
user.reauthenticateAndRetrieveDataWithCredential(credentials)
.then(() => {
user.updatePassword(this.new_password)
.then(() => {
console.log('your password was successfully changed.')
})
.catch(error => console.log(error))
})
.catch(error => console.log(error.message))
}
}
Where I was running into Cannot read property 'credential' of undefined"...
Importing only { auth } from './firebase.js and then calling auth.EmailAuthProvider().
How to access other classes found on firebase.auth()...
export const fb = firebase in firebase.js
import { fb, auth } from './firebase.js' where you are writing your function
Call fb.auth.EmailAuthProvider.credential() or other class needed
The documentation for reauthenticating the user shows this example:
var user = firebase.auth().currentUser;
var credential;
// Prompt the user to re-provide their sign-in credentials
user.reauthenticateAndRetrieveDataWithCredential(credential).then(function() {
// User re-authenticated.
}).catch(function(error) {
// An error happened.
});
Your code fails to implement the comment correctly. You will need to show a prompt to the user to provide their credentials again, put those into the correct credential object type, and pass that in.
For example:
var credential = firebase.auth.EmailAuthProvider.credential(
email,
password
);
You need to use a subscription to watch for the changes. Use AngularFire to watch for when they are logged in and get the UID (assuming you are using the Authentication login in Firebase so that all data is saved using the UID as the tree path.
You can also add a set timeout to unsubscribe them after a given time
import { AngularFirestore } from 'angularfire2/firestore';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { AngularFireAuth } from 'angularfire2/auth';
import { switchMap, map } from 'rxjs/operators';
import { Observable, pipe } from 'rxjs';
import { Observable, Subscription } from 'rxjs';
import firebase as firebase from 'firebase/app';
private myOAuthSubscription: Subscription;
private myDatasubscription: Subscription;
public userloggedin:boolean = false;
public uid:string = '';
private functionhasrun:boolean = false;
public this.items:any = [];
constructor(
public _DB: AngularFireDatabase,
public _afAuth: AngularFireAuth,
) {
//check that the user is logged in
try {
this.myOAuthSubscription = this._afAuth.authState.subscribe(user => {
if (user && user.uid) {
console.log('loggedin = true');
this.userloggedin = true;
this.uid = String(user.uid);
if(this.functionhasrun==false){
this.functionhasrun = true;
this.funDoDB():
}
} else {
console.log('loggedin = false');
this.userloggedin = true;
this.uid = '';
}
});
} catch (e) {
console.error("fbData_subscription", e);
}
}
ngOnDestroy() {
this.myOAuthSubscription.unsubscribe();
this.myDatasubscription.unsubscribe();
}
private funDoDB(){
if(this.userloggedin == true){
try {
//subscription using AngulaFire
this.myDatasubscription = this._DB.list('myDataPath/' + this.uid).snapshotChanges().pipe(map(actions => {
return actions.map(action => ({ key: action.key, val: action.payload.val() }));
}))
.subscribe(items => {
this.items = [];
this.items = items.map(item => item);
console.log("db results",this.items);
var icount=0;
for (let i in this.items) {
console.log("key",this.items[i].key);
console.log("val",this.items[i].val);
console.log("----------------------------------);
//checking if something exists
if (this.items[i].key == 'SomeNodePath') {
var log = this.items[i].val;
}
}
} catch (e) {
console.error(e);
}
});
}
}
npm install --save angularfire2 firebase
npm install -D rxjs#6.2.2 rxjs-compat#6.2.2
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();