Delete a user by email in lieu of UID Firebase - node.js

I am successfully deleting accounts with an account UID in a Firebase Function, but is it possible to delete an authenticated account via an email address vs. their UID?
This is what I have now:
admin.auth().getUserByEmail(userEmail).then(function(userRecord) {
// See the UserRecord reference doc for the conteenter code herents of userRecord.
console.log('Successfully fetched user data:', userRecord.toJSON());
admin.auth().deleteUser(userRecord)
.then(function
() {
console.log('This is the ID being used!', userRecord);
console.log('Successfully deleted user');
})
.catch(function(error) {
console.log('This is the ID being used!', userRecord);
console.log('Error deleting user:', error);
});
})
.catch(function(error) {
console.log('Error fetching user data:', error);
});
});
Thank you!

You can use deleteUser(uid) to delete the user account as a second operation after you find the account with getUserByEmail(). The UserRecord it returns has a uid field in it.
So, instead of what you're doing now:
admin.auth().deleteUser(userRecord)
Do this instead:
admin.auth().deleteUser(userRecord.uid)

The admin sdk don't have a method to delete by user so It's not posible to delete user with email. You could use the way that you mention.

Related

How to unlink Email from Firebase using Firebase Admin Node JS SDK

I'm trying to unlink Email to the current user that has a Phone Number and Email already linked to it.
here what I do :
admin.auth().updateUser("user uid", {
email: null,
password: null,
})
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully updated user', userRecord.toJSON());
})
.catch(function(error) {
console.log('Error removing email:', error);
});
but it was returning error The email address is improperly formatted.
for some reason, only when I remove the email this happen, when i do the same for phone its working :
admin.auth().updateUser("user uid", {
phoneNumber: null,
})
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully updated user', userRecord.toJSON());
})
.catch(function(error) {
console.log('Error removing phone number:', error);
});
The above code works, the phone is removed perfectly. but only when I do this to Email occurring error.
Is there something I miss?
UpdateRequest#email must be undefined or a valid email.
UpdateRequest#password must be undefined or an unhashed password.
You may be able to use:
admin.auth().updateUser("user uid", {
email: undefined,
password: undefined,
})
But you are often better off unlinking the EmailAuthProvider credential on the client.
firebase.auth().currentUser
.unlink(firebase.auth.EmailAuthProvider.PROVIDER_ID);
You can unlink providers with the admin sdk using the providersToUnlink
await auth.updateUser(user.uid, {
providersToUnlink: ['password'],
})

Android Firebase cloud function - delete user using email

i'm trying to delete a user from firebase auth using a cloud function which is triggered when i delete the document of the user. this is a workaround to enable one client "admin" permissions to delete other users without admin SDK. in the document i store the users email. how do i delete the user from auth using the email?
it should be something like this:
exports.sendDelVolunteer = functions.firestore.document('Users/{messageId}').onDelete((snap, context) => {
const doc = snap.data();
const user = admin.auth().getUserByEmail(doc.email).then(function(userRecord) {
return admin.auth().deleteUser(userRecord.uid).then(function() {
console.log('Successfully deleted user');
})
.catch(function(error) {
console.log('Error deleting user:', error);
});
}).catch(function(error) {
console.log('Error fetching user data:', error);
});
});
currently i get the following error: "error Each then() should return a value or throw"
thanks!!!
enter image description here
You're missing a top-level return statement.
exports.sendDelVolunteer = functions.firestore.document('Users/{messageId}').onDelete((snap, context) => {
const doc = snap.data();
return admin.auth().getUserByEmail(doc.email).then(function(userRecord) {
return admin.auth().deleteUser(userRecord.uid)
});
});
Aside from that this looks like a good approach. Just make sure that only your administrator(s( can delete these documents, as otherwise you still have a security hole.

How to change display name in firebase cloud functions?

I am trying to build a firebase cloud function to change a display name.
I know that i can do it easily in android, but since every time i change the display name i need to update all user records and since there isn't seem to be a way to get notified in firebase function when display name has changed (please correct me if i am wrong), i am planning to make the change in firebase and on the same time make the records update.
This is how i started...
exports.changeDisplayName = functions.https.onCall((data,context) => {
console.log(`User ${context.auth.uid} has requested to change its display name`);
//If user not authenitacted, throw an error
if (!(context.auth && context.auth.token && (context.auth.token.firebase.sign_in_provider === 'phone'))) {
if (!context.auth) {
console.log(`User ${context.auth.uid} without auth`);
}
if (!context.auth.token) {
console.log(`User ${context.auth.uid} without token`);
}
if (!context.auth.token.phoneNumber) {
console.log(`User ${context.auth.uid} without phone number (${context.auth.token.firebase.sign_in_provider})`);
}
throw new functions.https.HttpsError(
'permission-denied',
'Must be an authenticated user with cellphone to change display name'
);
}
// Change display display name from data
// update firebase contacts
});
To update a user's name from Cloud Functions, you'll be using the Firebase Admin SDK for Node.js users. Through that, you can update any properties of a user profile with something like this:
admin.auth().updateUser(uid, {
email: 'modifiedUser#example.com',
phoneNumber: '+11234567890',
emailVerified: true,
password: 'newPassword',
displayName: 'Jane Doe',
photoURL: 'http://www.example.com/12345678/photo.png',
disabled: true
})
.then(function(userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully updated user', userRecord.toJSON());
})
.catch(function(error) {
console.log('Error updating user:', error);
});

Handling Stripe errors with Node.JS

I am attempting to charge a user when they create an account. Everything is set up and working perfect with the code before. When a user sign's up for a "premium" section of the website they have an account created and are charged with the code below.
The problem: If a user's credit card ends up getting declined for various reasons... their user account is STILL created. How would I change my code below to not reach that part of the code if the credit card fails?
Note: this DOES work for when the user trys to create an account with a username that is taken. The web app redirects them to /buy to select a new username. However it does not work to handle the credit card errors because the user is created first.
Thank you for the help!
user.save(function(err) {
console.log('this is the problem' + ' ' + err)
if(err){
return res.redirect('/buy')
}
var token = req.body.stripeToken; // Using Express
var charge = stripe.charges.create({
amount: 749,
currency: "usd",
description: "Website.com Premium - One time Payment",
source: token,
}, function(err, charge) {
if(err) {
console.log(err);
return res.redirect('/buy')
}
console.log('charged')
req.logIn(user, function(err) {
if(err) {
console.log(err);
}
console.log('all looks good')
res.redirect('/results');
});
});
});
});

Update logged in user details in session

I am using PassportJS with ExpressJS.
I need to update the logged in user details. While I do update this in the DB, how do I update it in the session too so that request.user contains the updated user details?
That is, after updating the database, how do I update the session info on the user as well?
I tried directly assigning the updated details to request.user but it did not work.
I then tried request.session.passport.user - this worked but there is a delay of around 5 to 10 seconds before it gets updated in request.user too.
Is there a function that I need to call that updates the user information stored in the session? Or is there some other object that I can update where the change does not have a delay
I've been hunting down an answer for this too. Never mentioned in any docs or tutorials!
What seems to work is, after saving your newly updated user, do req.login(user)...
// "user" is the user with newly updated info
user.save(function(err) {
if (err) return next(err)
// What's happening in passport's session? Check a specific field...
console.log("Before relogin: "+req.session.passport.user.changedField)
req.login(user, function(err) {
if (err) return next(err)
console.log("After relogin: "+req.session.passport.user.changedField)
res.send(200)
})
})
The clue was here... https://github.com/jaredhanson/passport/issues/208
User.findById(req.user._id,function(err,doc){
req.logIn(doc,function(err1){
if(err1){ console.log("Error : "+err1) }
else{
res.render("abc.ejs",{user:req.user});
console.log('Item Removed Successfully!!!');
}
});
});
Here we are re-login the user
User => Mongoose Model
I had similar problem today and decided to share my findings, since i couldn't find similar answer.
The problem was that (copied from passport documentation) i was getting the user data directly from the token, that the user sent in the request. Which was of course outdated.
passport.use(new JWTStrategy({
jwtFromRequest: ExtractJWT.fromAuthHeaderAsBearerToken(),
secretOrKey : CONFIG.JWT_SECRET
},
function (jwtPayload, cb) {
return cb(null, jwtPayload);
}
));
while i should get the fresh user object from the database instead:
return User.findById(jwtPayload.id)
.then(user => {
return cb(null, user);
})
.catch(err => {
return cb(err);
});

Resources