Firebase update user data from firebase function - javascript

I am trying to update user data using firebase function, it's working fine when update user display name. My issue here is below function not updating the user password through firebase function.
exports.updateUserPassword = functions.https.onCall(async (data, context) => {
try {
return await authAppAdmin.auth().getUserByEmail(data.email)
.then((userPassUpdate) => {
console.log(userPassUpdate.uid);
return authAppAdmin.auth().updateUser(userPassUpdate.uid,
{
password: data.newPassword,
displayName: data.displayName
});
})
.catch((error) => console.log(error["message"]));
} catch (error) {
return error;
}
});
Many thanks in advance.

Can you try the following code? I have doubts it will solve your problem but I think we should give a try. If you still get the same problem I'll delete this answer.
It is important that you copy the three first lines and use admin.auth().... Also this code should normally correctly log any error.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.updateUserPassword = functions.https.onCall(async (data, context) => {
try {
const userPassUpdate = await admin.auth().getUserByEmail(data.email)
console.log(data.newPassword);
console.log(userPassUpdate.uid);
await admin.auth().updateUser(
userPassUpdate.uid,
{
password: data.newPassword,
displayName: data.displayName
});
return { result: "OK" }
} catch (error) {
console.log(error);
throw new functions.https.HttpsError('internal', JSON.stringify(error)); // See https://firebase.google.com/docs/functions/callable#handle_errors
}
});

Related

Axios response data is not saved with useState

While trying to fetch data from my express backend and MySQL database, with my react frontend using axios, it fails to set the fetched data using useState
my frontend function looks like this
const searchUser = () => {
Axios.post("http://localhost:3001/searchUser", {
username: username,
}).then((response) => {
if (response.data) {
setResult(response.data);
}
});
};
and my backend function looks like this
const searchUser = (req, res) => {
const keyword = req.body.username;
db.query(
"SELECT id,username FROM users WHERE username like ?",
"%" + keyword + "%",
(err, result) => {
if (err) {
res.json({ message: err });
console.log(err);
} else {
console.log(result);
res.json({ result });
}
}
);
};
I tried many methods while saving the data with the useState hook, I appreciate any help
While using Promises and then instead of async / await make sure to catch the errors if your fetch fails.
Unless you share with us the whole component that contains the searchUser function and how you defined the state i cannot pin point you on the error.
What i suggest you to do is adding a catch to your fetch by doing the following:
const searchUser = () => {
Axios.post("http://localhost:3001/searchUser", {
username: username,
}).then((response) => {
if (response.data) {
setResult(response.data);
}
}).catch((error) => {
console.error(error);
});
};
If any abnormalities has happened in your request the catch will tell you! Don't underestimate it's power.
Another path you can look into is console logging your output in front end searchUser function just before setting it in the state.
I did solve the problem, just by replacing res.json({ result }); to res.json(result); in the last line in my backend function

Adding document to a collection within .then of firebase auth.createUserWithEmailAndPassword

With VueJS and Firebase, I want to create a user and then if it succeed add more info to a users collection.
Problem is my variable usersCollection is undefined when I get in the .then. I know I can take that exact code out of the .then and it works. Also, the auth function works as it is supposed to. It would seem that the problem is that I'm trying to access the collection inside the .then. But then again, I need to do this only if I successfully create a new user for authentication to avoid having users info from unregistered users. I don't enter the .catch either and I don't get an error of any kind in the chrome console. Any idea how to get this logic to work?
I initialize everything about firebase with this :
import * as firebase from 'firebase/app'
import 'firebase/auth'
import 'firebase/firestore'
import 'firebase/analytics'
const firebaseConfig = {
//configs
};
firebase.initializeApp(firebaseConfig);
firebase.analytics();
const db = firebase.firestore();
const auth = firebase.auth();
const usersCollection = db.collection('users');
export {
db,
auth,
usersCollection
}
The code is located in the main store of the app :
import * as types from './types';
import {
auth,
usersCollection,
} from '../../../../config/firebase';
//...
[types.ADD]: ({commit}, user) => {
auth.createUserWithEmailAndPassword(user.email, user.password)
.then((e) => {
usersCollection.add(user)
.then((docRef) => {
commit(types.MUTATE_ADD, user);
console.log("Document written with ID: ", docRef.id);
})
.catch((error) => {
console.error("Error adding document: ", error);
});
})
.catch((e) => {
//...
alert('An error occured while creating employee.\n' + e.code + '\n' + e.message);
return false;
});
}
Above, the the user I use for authentication is created, but when I get to the .then usersCollection is undefined, yet I get no error in the Chrome console and the user is not created.
As explained earlier, if I take the block where I add the user to the collection out of the .then I get to add the user to the collection :
[types.ADD]: ({commit}, user) => {
auth.createUserWithEmailAndPassword(user.email, employeeHelper.makePassword(user))
.then((e) => {
})
.catch((e) => {
var errorCode = e.code;
var errorMessage = e.message;
alert('An error occured while creating employee.\n' + e.code + '\n' + e.message);
return false;
});
usersCollection.add(user)
.catch((error) => {
console.error("Error adding document: ", error);
});
}
Using another method made it work exactly as I intended :
[types.ADD]: ({commit}, user) => {
commit(types.MUTATE_ADD, user);
auth.createUserWithEmailAndPassword(user.email, employeeHelper.makePassword(user))
.then((e) => {
usersCollection.doc(user.email).get().then((querySnapshot) => {
querySnapshot.ref.set(user).then(() => {
//log success
})
}).catch((e) => {
console.log(e);
//log error
})
})
.catch((e) => {
//log error
return false;
});
}
The difference is that instead of using .add() method on my usersCollection, I used .doc(user.email).get().then(...) and I set data afterwards instead of using .add(...). For some reason, the Chrome console still shows usersCollection as if it is undefined if I put a breakpoint there :
usersCollection.doc(user.email).get().then((querySnapshot) => {
But the data is properly pushed to firestore nonetheless. So I'm not completely comfortable with the fact that I don't know why it works this way but not the other, but the result is exactly what I needed even though I suspect it creates some overhead.

Receiving [Error: Internal] in RN app when triggering a Cloud Function

I have a Google Cloud Function which I am calling from my RN app but it is returning
[Error: Internal]
I have set the permission to Unauthenticated users so anyone can call it - for testing purposes only. When I set to Authenticated users permission, it throws another error [Error: Unauthenticated] eventhough I am authenticated and I can get the currentUser id in my app.
Tried searching for this error but it didnt send me to any possible solutions so decided to post here and hopefully recieve responses that will help me fix it.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.createUser = functions.region('europe-west1').https.onCall(async (data, context) => {
try {
//Checking that the user calling the Cloud Function is authenticated
if (!context.auth) {
throw new UnauthenticatedError('The user is not authenticated. Only authenticated Admin users can create new users.');
}
const newUser = {
email: data.email,
emailVerified: false,
password: data.password,
disabled: false
}
const role = data.role;
const userRecord = await admin
.auth()
.createUser(newUser);
const userId = userRecord.uid;
const claims = {};
claims[role] = true;
await admin.auth().setCustomUserClaims(userId, claims);
return { result: 'The new user has been successfully created.' };
} catch (error) {
if (error.type === 'UnauthenticatedError') {
throw new functions.https.HttpsError('unauthenticated', error.message);
} else if (error.type === 'NotAnAdminError' || error.type === 'InvalidRoleError') {
throw new functions.https.HttpsError('failed-precondition', error.message);
} else {
throw new functions.https.HttpsError('internal', error.message);
}
}
});
in my RN app I am calling it like this:
var user = {
role: role
}
const defaultApp = firebase.app();
const functionsForRegion = defaultApp.functions('europe-west1');
const createUser = await functionsForRegion.httpsCallable('createUser');
createUser(user)
.then((resp) => {
//Display success
});
console.log(resp.data.result);
})
.catch((error) => {
console.log("Error on register patient: ", error)
});
I think the way I am calling it in my RN app is correct because I have tested it with a testFunction and I returned a simple string. So, I believe the problem is somewhere in the function itself.
EDIT: I just tested by simply calling the function and returning the context and it always returns Internal error:
exports.registerNewPatient = functions.region('europe-west3').https.onCall((data, context) => {
return context; //this is returned as INTERNAL error.
}
I just cant get to understand whats going on here, why does it return Internal error when I am authenticated as a user and it should return the authenticated user data, isn't that right?
Try some console.log(context) ; console.log(data) statements in your registerNewPatient function and take a look at the logs. What do they say?
Some other things to consider might include that in your client code you use europe-west1 while your function code has europe-west3. Try to have those line up and see if it works? From my experience, if a specified function isn't found to exist, the client receives an INTERNAL error.

Error: Node.js module defined by file index.js is expected to export function named xxxx

Hello there dev community. I´m trying to debug a firebase function and being trying using several tutorials, but with no success...
I´ve tried
(https://medium.com/#mwebler/debugging-firebase-functions-with-vs-code-3afab528bb36)
(https://medium.com/#david_mccoy/build-and-debug-firebase-functions-in-vscode-73efb76166cf)
My purpose is to get google contacts.
functions/index.js
const { google } = require('googleapis');
const oauthUserCredential = require('./oauthUserCredential.json')
const OAuth2 = google.auth.OAuth2
const key = require('./serviceAccountKey.json')
const jwt = new google.auth.JWT(key.client_email, null, key.private_key, 'https://www.googleapis.com/auth/contacts')
exports.getGoogleContacts = functions.https.onCall(async (data, context) => {
const requestingUser = data.requestingUser
console.log('getGoogleContacts-requestingUser', requestingUser)
const oauth2Client = new google.auth.OAuth2(
'client_id',
'client_secret',
'http://localhost:5000/xxx-xxx/us-central1/OAuthCallbackUrl'
);
const contacts = google.people({
version: 'v1',
auth: oauth2Client,
});
console.log('contacts ?', contacts)
(async () => {
const { data: groups } = await contacts.people.get({
resourceName: 'contactGroups',
});
console.log('Contact Groups:\n', groups);
})()
jwt.authorize((err, response) => {
console.log('inside authorize')
if (err) {
console.error(err);
response.end();
return;
}
// Make an authorized request to list contacts.
contacts.people.connections.list({
auth: authClient,
resourceName: 'people/me'
}, function (err, resp) {
if (err) {
console.error(err);
response.end();
return;
}
console.log("Success");
console.log(resp);
response.send(resp);
});
});
// this is another approach I´ve tried, but it´s also not working
const oAuth2Client = new OAuth2(
oauthUserCredential.web.client_id,
oauthUserCredential.web.client_secret,
oauthUserCredential.web.redirect_uris,
)
oAuth2Client.setCredentials({
refresh_token: oauthUserCredential.refresh_token
})
return new Promise((resolve, reject) => {
console.log('[INSIDE PEOPLE CONNECTIONS]')
contacts.people.connections.list({
auth: oauth2Client //authetication object generated in step-3
}, function (err, response) {
if (err) {
console.log('contacts.people.connections error')
console.log(err)
reject(new Error(err))
} else if (response) {
console.log('contacts.people.connections response')
console.log(response)
resolve(response)
}
});
})
.then(result => { return { found: result } })
.catch(err => { return { error: err } })
})
I´ve tried several different approachs and followed different tutorials
(Using Google People API with Cloud Functions for Firebase)
(https://flaviocopes.com/google-api-authentication/)
(https://medium.com/#smccartney09/integrating-firebase-cloud-functions-with-google-calendar-api-9a5ac042e869)
(https://cloud.google.com/community/tutorials/cloud-functions-oauth-gmail)
but none of them show clearly how could I get my contacts list.
I was able to use a client side code by following this tutorial (https://labs.magnet.me/nerds/2015/05/11/importing-google-contacts-with-javascript.html)
but I thought that living the client_id, client_secret and apiKey exposed in the client side would be a security problem...
I´m submitting also a tutorial request to make it very clear how to get contacts list from google account using firebase functions.
The Error you are receiving is because the cloud function cannot find the function named xxxx to execute, as you have not defined any function named xxxx in the index.js file.
Your Cloud Function to execute name, according to the error message is xxxx but the function that you are calling in index.js is getGoogleContacts. Please make sure that these names are the same, for example change getGoogleContacts to xxxx or change function to execute to getGoogleContacts

can't update user's email

I am trying to update the email of the current user, I went to documentation and I copied the example code that they are given there,
But nothing worked, this from doc didn't work
var user = firebase.auth().currentUser;
user.updateEmail("newemail#example.com").then(function() {
console.log('success')
}).catch(function(error) {
console.log('failed')
});
I have also tried :
try {
await user.updateEmail('test#test.com').then(function() {
console.log('success')
}).catch(function(error) {
handleErrors(dispatch, error.message);
});
} catch(e) {
handleErrors(dispatch, e.message);
}
could you help to solve this issue?
update :
sorry i didn't include the exact error that come out in the console , here is the error :
This operation is sensitive and requires recent authentication. Log in
again before retrying this request.
2)
I should add that I am using asyncstorage of react native , and I store that Item( profile of user => email , name , ect..) in reduxPersist
that how my login code is :
export const login = ( email, password ) => {
return async (dispatch) => {
dispatch({ type: ATTEMPTING });
try {
await firebase.auth().signInWithEmailAndPassword(email, password)
.then(resp => handleLoginSuccess(dispatch, resp.uid,resp.name,email))
.catch(error => handleErrorLogin(dispatch, error.message));
}catch(e){
handleErrorLogin(dispatch, e.message);
}
};
};
const handleLoginSuccess = async(dispatch , userId,name,email) => {
try{
const profile = { userId, name, email };
await AsyncStorage.setItem('userProfile', JSON.stringify(profile));
dispatch({ type: LOGIN_SUCCESS, payload: profile });
}catch(e){
alert(e.message);
}
}
The error message is telling you that there is no user logged in at the time you call updateEmail. The SDK doesn't know which user you're trying to modify. You'll need to wait until the login is fully complete before calling that method.
Note that all of the Firebase APIs are asynchronous, so you'll need to make use of their returned promises to make sure the order of calls is valid.

Categories

Resources