How to change display name in firebase cloud functions? - node.js

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);
});

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.

Create users with email an phone provider using Admin Firebase

How can one create a user with phone number and email as providers in Firebase?
The code presented only sets up the phone number as being the only provider.
admin.auth().createUser({
uid: email,
email: email,
emailVerified: true,
phoneNumber: checkMobileTel(mobileTel)
})
.then(function(userRecord: { uid: any; }) {
// See the UserRecord reference doc for the contents of userRecord.
console.log('Successfully created new user:', userRecord.uid);
})
.catch(function(error: any) {
console.log('Error creating new user:', error);
});
I think you are forgetting to add the password field. I hope I could help, happy coding!
password string The user's raw, unhashed password. Must be at least six characters long.

Firebase Admin SDK - Create user with custom fields

I've been following the Firebase SDK Admin - Manager User docs and everything went find for me with it's system. Either way, i want to extend my users information with fields such as first name, last name, nacionality, etc etc.
Right now i'm using Vue.JS (fronted), Axios (Http client) and Express.js (server) to manage my project and this is the way i create my users:
Vue.JS createUser method:
createUser() {
axios.post('http://localhost:3000/users',
{
username: this.username,
email: this.email,
firstName: this.firstName,
lastName: this.lastName,
password: this.password,
}).then(r => {
console.log(r)
}).catch(e => {
console.log(e)
})
// createUser
}
Each field: username, email, firstName, etc... got its value form a common HTML Form and they work just fine.
This is my "user create" route on the server side:
router.post('/', function (req, res, next) {
firebase.auth().createUser({
email: req.body.email,
username: req.body.username,
firstName: req.body.firstName,
lastName: req.body.lastName,
emailVerified: false,
password: req.body.password,
disabled: false
}).then(function(userRecord) {
console.log("Successfully created new user:", userRecord.uid);
}).catch(function(error) {
console.log("Error creating new user:", error);
});
});
And this is how i retrieve the users information:
router.get('/', function(req, res, next) {
firebase.auth().listUsers()
.then(function(listUsersResult) {
res.send(listUsersResult.users);
}).catch(function(error) {
console.log("Error listing users:", error);
})
});
The problem is that i can't get the custom fields i added (or they simply does not exists). Here's is a pictures of the data once i get it with the next method:
getItems() {
axios.get('http://localhost:3000/users').then(r => {
this.users = r.data
}).catch(e => {
console.log(e)
})
},
Is there a way to set custom fields on my user creation or (if my process is right) a way to retrieve them?
Firebase users are not customizable, unfortunately you can not add custom fields to the user... check out these docs for the properties of this object. Also check out this question & answer where Frank explains that you need to store any extra info separately... this is typically done in a table (named something like /userDetails) in your database.
FEBRUARY 2022 EDIT:
Since writing this answer, custom user claims are now a thing. It's meant for authentication / rules purposes and not data-storage, so most things should still be kept in the database as originally stated. Note that you CAN access the custom fields client-side.
Keep in mind, this is adding additional data to the ID token that gets sent with EVERY server request, so you should try to limit usage of this to role/permission based things and not, say, image data for a 2nd profile avatar. Read the best practices for custom claims on the official docs.
You can set a user's profile, immediately after creating.
firebase.auth().createUserWithEmailAndPassword(
email,
password,
).then(credential => {
if (credential) {
credential.user.updateProfile({
displayName: username
})
}
}

firebase temporarily sending "There is no user record"?

I'm trying to make a simple web application and trying to implement google authentication(login) using passport and store the user in firebase authentication.
So, in the passport middleware what i do is check if the user is authenticated.
if yes then pass the user to the passport.serializeUser(user) else create the user in firebase authentication. and then pass the user to passport.serializeUser(user)
here is a pseudo code -
if (user.authenticated){
done(null, user)
} else {
let promise = {'uid': user.uid, 'name': user.displayName, 'picture':user.photos[0].value};
firebase.auth().createUser({
uid: user.uid,
displayName: user.name,
photoURL: user.picture
});
console.log('i have submitted the user')
done(null, promise)
}
everything is going cool the passport.serializeUser() gets and the user calls done(null, user.uid).
the problem hits when the passport.deserializeUser().
i dont do any fancy there but just get the user from the firebase by using firebase.auth().getUser(id) where it gives me an error.
here is my code for passport.deserializeUser().
passport.deserializeUser((id, done) => { // when we get a request
console.log(`deser id ${id}`); // it shows the id we passed in serialize
firebase.auth().getUser(id).then( // gives an error T_T ?
(user) => {
console.log(`deser data ${user}`); // IT SHOULD GO HERE
done(null, user)
}).catch((error) => { // it goes here and throws an error at me
console.log(`here is the error on deser ${error}`);
// here is the error on deser Error: There is no user record corresponding to the provided identifier.
});
});
the magic happens after some time when the passport.deserealizeUser() gets called again at now for some reason it doesn't throw a error at me.
here is the console log..
i have submitted the user
ser // i do this call in passport.serializeUser()
deser id "someid"
here is the error on deser Error: There is no user record corresponding to the provided identifier.
deser id "someid"
deser data [object Object]
my question is that why does the firebase being delayed?
is it because of the reason that first time the firebase didn't loaded and the second time it loaded and was successful to find the user?
but what could be the reason for that?
any guesses?
Alright guys So, after a big nap I've found out what I did wrong, i wasn't handling the promise from the..
firebase.auth().createUser({
uid: user.uid,
displayName: user.name,
photoURL: user.picture
});
so what i did is like ..
firebase.auth().createUser({
uid: user.uid,
displayName: user.name,
photoURL: user.picture
}).then((user) => {
done(null, user);
});
certainly it requires some time to process the user in the auth() ..
that is why.
ALWAYS USE PROMISES.

Resources