How to linkWithCredential after you delete current user? - javascript

In my app, I'm trying following the documentation for how to link multiple auths in Firebase, but when I follow the example for linking to a pre-existing account linkWithCredential fails with an error of No user currently signed in.
// Get reference to the currently signed-in user
let prevUser = firebase.auth().currentUser;
// Sign in user with another account
firebase.auth().signInWithCredential(_credential).then((user) => {
let currentUser = user.user;
// Merge prevUser and currentUser data stored in Firebase.
// Note: How you handle this is specific to your application
// After data is migrated delete the duplicate user
return currentUser.delete().then(() => {
// Link the OAuth Credential to original account
console.log("!!DELETE FACEBOOK")
return prevUser.linkWithCredential(_credential).then(() => {
console.log("!!LINKING-FACEBOOK")
}).catch((error) => {
console.log("!!LINKING ERROR", error)
});
}).then(() => {
console.log("!!SIGNIN-LINKED")
// Sign in with the newly linked credential
return firebase.auth().signInWithCredential(_credential)
});
}).catch((error) => {
console.log("Sign In Error", error);
});
What I'm confused about is how can I can re-sign in to my previous account in order to be able to link the newly deleted account credentials to it?

Related

why old Email returns after updating it in firebase and VUE.JS?

am trying to allow users to change their primary email in my VUE App which uses firebase as authentication,
the code am using works fine and it gives me that the email has been updated, however after the email is updated I can log with the new email for one time only and once I have logged out then like it has never been changed, and the old email is working again.
What is am doing wrong that keeps getting the old email assigned with the user
currently am using the following code :
firebase.auth()
.signInWithEmailAndPassword(oldEmailAddress, currentPass)
.then(
() => {
firebase.auth().currentUser.updateEmail(newEmailAddress).then(() => {
console.log('Email Updated');
}).catch((error) => {
console.log('Email Error updating user:', error);
});
},
(err) => {
console.log('log in user error:', err);
}
);
try using this function from firebase/auth as the docs say:
const auth = getAuth();
updateEmail(auth.currentUser, "user#example.com").then((result) = { console.log(result) })

Password is gone when logging in a firebase account that was created using Email and Password

I created an app that supports both Email/Password and Google authentication. I found that if I created an account in a first way, but logged out and in again with Google, the origin password was gone, and no way to sign in with email anymore. Is there any way to avoid so?
// Google authentication
const signInWithGoogle = useCallback(
async event => {
event.preventDefault();
const provider = new firebase.auth.GoogleAuthProvider();
try {
await firebaseApp
.auth()
.signInWithRedirect(provider)
.then(function(result) {
var user = result.user.providerId;
alert(user);
});
history.push("/transfer");
} catch(error) {
alert(error.message);
}
},
[history]
);
//Email/Password sign-in
const handleLogin = useCallback(
async event => {
event.preventDefault();
const { email, password } = event.target.elements;
try {
await firebaseApp
.auth()
.signInWithEmailAndPassword(email.value, password.value)
.then(function(result) {
var user = result.user.providerId;
alert(user);
});
history.push("/transfer");
} catch (error) {
alert(error);
}
},
[history]
);
// Email/Password sign-up
const handleSignUp = useCallback(async event => {
event.preventDefault();
const { email, password } = event.target.elements;
try {
await firebaseApp
.auth()
.createUserWithEmailAndPassword(email.value, password.value);
history.push("/usersignupcred");
} catch (error) {
alert(error);
}
}, [history]);
Here in the documentation you can see this explanation:
Note that some providers, such as Google and Microsoft, serve as both email and social identity providers. Email providers are considered authoritative for all addresses related to their hosted email domain. This means a user logging in with an email address hosted by the same provider will never raise this error (for example, signing in with Google using an #gmail.com email, or Microsoft using an #live.com or #outlook.com email).
I would recommend to use as similar approach like here from the docu:
// User tries to sign in with Facebook.
auth.signInWithPopup(new firebase.auth.FacebookAuthProvider()).catch(err => {
// User's email already exists.
if (err.code === 'auth/account-exists-with-different-credential') {
// The pending Facebook credential.
var pendingCred = err.credential;
// The provider account's email address.
var email = err.email;
// Get the sign-in methods for this email.
auth.fetchSignInMethodsForEmail(email).then(methods => {
// If the user has several sign-in methods, the first method
// in the list will be the "recommended" method to use.
if (methods[0] === 'password') {
// TODO: Ask the user for their password.
// In real scenario, you should handle this asynchronously.
var password = promptUserForPassword();
auth.signInWithEmailAndPassword(email, password).then(result => {
return result.user.linkWithCredential(pendingCred);
}).then(() => {
// Facebook account successfully linked to the existing user.
goToApp();
});
return;
}
// All other cases are external providers.
// Construct provider object for that provider.
// TODO: Implement getProviderForProviderId.
var provider = getProviderForProviderId(methods[0]);
// At this point, you should let the user know that they already have an
// account with a different provider, and validate they want to sign in
// with the new provider.
// Note: Browsers usually block popups triggered asynchronously, so in
// real app, you should ask the user to click on a "Continue" button
// that will trigger signInWithPopup().
auth.signInWithPopup(provider).then(result => {
// Note: Identity Platform doesn't control the provider's sign-in
// flow, so it's possible for the user to sign in with an account
// with a different email from the first one.
// Link the Facebook credential. We have access to the pending
// credential, so we can directly call the link method.
result.user.linkWithCredential(pendingCred).then(usercred => {
// Success.
goToApp();
});
});
});
}
});
But instead of waiting for the error to be raised (none will be raised if using Google login as you also explained in your case) try always to call first fetchSignInMethodsForEmail and if the user has the email provider and tries now to use the Google one first log him in with the email provider and link him later with the Google provider.

Send verification email before logging in

This is the code that i'm practicing in to create a new user. I can receive the email verification and confirm it however, the site will still logged me in even if I have not yet confirmed my email yet.
try{
const { user } = await auth.createUserWithEmailAndPassword(email,password);
await user.sendEmailVerification();
await handleUserProfile(user, { displayName});
this.setState({
...initialSate
});
}catch(err){
console.log(err);
}
}
This is the handleUserProfile in another js file.
export const handleUserProfile = async (userAuth, additionalData) => {
if (!userAuth) return;
const {uid} = userAuth;
const userRef = firestore.doc(`users/${uid}`);
//create new user
const snapshot = await userRef.get();
if (!snapshot.exists){
const { displayName, email} = userAuth;
const timestamp = new Date();
//if the user exist does not exist
try{
await userRef.set({
displayName,
email,
createdDate: timestamp,
...additionalData
});
}catch(err){
console.log(err);
}
}
return userRef;
};
Everything is explained in the firebase documentation.
There you have the corresponding code snippets to try.
You would need to narrow down your question with some of this trials.
Even you have the chance to check if user opens the link from a differenc device from which waas signed up.
I think this is the snippet you might need:
// Confirm the link is a sign-in with email link.
if (firebase.auth().isSignInWithEmailLink(window.location.href)) {
// Additional state parameters can also be passed via URL.
// This can be used to continue the user's intended action before triggering
// the sign-in operation.
// Get the email if available. This should be available if the user completes
// the flow on the same device where they started it.
var email = window.localStorage.getItem('emailForSignIn');
if (!email) {
// User opened the link on a different device. To prevent session fixation
// attacks, ask the user to provide the associated email again. For example:
email = window.prompt('Please provide your email for confirmation');
}
// The client SDK will parse the code from the link for you.
firebase.auth().signInWithEmailLink(email, window.location.href)
.then((result) => {
// Clear email from storage.
window.localStorage.removeItem('emailForSignIn');
// You can access the new user via result.user
// Additional user info profile not available via:
// result.additionalUserInfo.profile == null
// You can check if the user is new or existing:
// result.additionalUserInfo.isNewUser
})
.catch((error) => {
// Some error occurred, you can inspect the code: error.code
// Common errors could be invalid email and invalid or expired OTPs.
});
}
The site will still logged me in even if I have not yet confirmed my
email yet.
Yes this is how it is implemented in Firebase: there is nothing, out of the box, that prevents a user with a non-verified email to authenticate to your app.
You should manage that yourself, by:
Checking the email is verified in the back-end security rules (Firestore, Cloud Storage, etc..). For example with a function like:
function isVerifiedEmailUser() {
return request.auth.token.email_verified == true;
}
Possibly redirect and logout the user from your app if his/her email is not verified. For example, right after signing-up, as follows:
try {
const { user } = await auth.createUserWithEmailAndPassword(email,password);
await user.sendEmailVerification();
if (user.emailVerified) {
// display the content, redirect to another page, etc...
} else {
auth.signOut(); // Maybe call that after showing an error message
}
} catch(err){
console.log(err);
}
}
plus, potentially, something similar with signInWithEmailAndPassword() and onAuthStateChanged().

How to set the user as logged in on firebase.auth(node.js)?

I have an app using sign in with a custom token, written on webpack observes. What I want to do now is mark the user after successful login by custom token as logged on firebase auth and firebase firestore, where I have the collections with users, and document for each user with data and some uid. I don't know how to to that.
Here is my code:
generateToken(uid) {
const uid = 'some-uid';
this.trigger(this.signals.action.onGenerateToken);
firebase.admin.auth().createCustomToken(uid)
.then((customToken) => {
console.log(customToken);
})
.catch(function (error){
if (error.Code === 'auth/invalid-custom-token') {
alert('The token you provided is not valid.');
}
else {
this.trigger(this.signals.error.onGenerateToken);
}
})
}
login(uid) {
firebase.auth().signInWithCustomToken(token)
.then(function() {
var user = firebase.auth().currentUser;
if (user) {
//mark the user as active (logged) after successful login on firebase auth and firebase firestore
};
this.trigger(this.signals.success.onLogin);
})
.catch(function(error) {
if (errorCode === 'auth/too-many-requests') {
this.trigger(this.signals.error.tooManyRequests);
}
else {
this.trigger(this.signals.error.userDisabled);
}
});
}
If I understand your question correctly, first create a reference to your user document, then call update() on the reference and pass in an object containing the properties you want to update and their new values.
let userRef = firebase.database().ref('users/' + userId);
userRef.update({active:true});
Check the firebase docs for more info on how to read and write to firebase.

result.user.link is not a function in angular firebase

Not able to link facebook account with an existing firebase account. I currently have a firebase account in that I created using google credentials. Now I want to link a facebook account with this exiting firebase account (both having same creadentials) and I followed the steps mentioned here :
https://firebase.google.com/docs/auth/web/facebook-login
But at last, when I call method "result.user.link(pendingCred).then( (user) => { .. }" to link account I get following error in console :
Uncaught TypeError: result.user.link is not a function
at auth.service.ts:188
at e.g (auth.js:23)
at Yb (auth.js:26)
at Ub (auth.js:26)
at z.webpackJsonp.../../../../#firebase/auth/dist/auth.js.h.Mb (auth.js:25)
at Cb (auth.js:19)
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invoke (zone.js:392)
at Zone.webpackJsonp.../../../../zone.js/dist/zone.js.Zone.run (zone.js:142)
at zone.js:873
at ZoneDelegate.webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:425)
Here is my code
loginFacebook(): Promise<any> {
return this.afAuth.auth.signInWithPopup(new firebase.auth.FacebookAuthProvider())
.then( (result) => {
this.registerUserName = result.user.displayName;
this.authDbUsername = result.user.email.replace('.', '');
// this.setLoggedinUser(user)
})
.catch ( (error) => {
if (error.code === 'auth/account-exists-with-different-credential') {
alert('You have already signed up with a different auth provider for that email.');
const pendingCred = error.credential;
// The provider account's email address.
const email = error.email;
// Get registered providers for this email.
firebase.auth().fetchProvidersForEmail(email).then( (providers) => {
// Step 3.
// If the user has several providers,
// the first provider in the list will be the "recommended" provider to use.
if (providers[0] === 'password') {
// Asks the user his password.
// In real scenario, you should handle this asynchronously.
const password = this.promptUserForPassword(providers[0]); // TODO: implement promptUserForPassword.
firebase.auth().signInWithEmailAndPassword(email, password).then( (user) => {
// Step 4a.
return user.link(pendingCred);
}).then(function( user) {
// Google account successfully linked to the existing Firebase user.
this.authState = user;
});
return;
}
// All the other cases are external providers.
// Construct provider object for that provider.
// TODO: implement getProviderForProviderId.
const provider = new firebase.auth.GoogleAuthProvider(); // this.getProviderForProviderId(providers[0]);
// At this point, you should let the user know that he already has an account
// but with a different provider, and let him validate the fact he wants to
// sign in with this provider.
// Sign in to provider. Note: browsers usually block popup triggered asynchronously,
// so in real scenario you should ask the user to click on a "continue" button
// that will trigger the signInWithPopup.
firebase.auth().signInWithPopup(provider).then( (result) => {
// Remember that the user may have signed in with an account that has a different email
// address than the first one. This can happen as Firebase doesn't control the provider's
// sign in flow and the user is free to login using whichever account he owns.
// Step 4b.
// Link to Google credential.
// As we have access to the pending credential, we can directly call the link method.
const resultingUser = result.user;
result.user.link(pendingCred).then( (user) => {
// Google account successfully linked to the existing Firebase user.
this.authState = user; // goToApp();
}).catch( (errorInLinking) => {
console.log(errorInLinking);
});
});
});
}
});
}
Please let me know if I am missing anything.
Thanks!
Change to result.user.linkWithCredential(pendingCred).then( (user) ...
link has been deprecated in favor of linkWithCredential starting from version 4.0.0.

Categories

Resources