Im getting an error for firebase's signInWithCredential - firebase

In my expo react native app, I use firebase and expo to authenticate. But when I try to run signInWithCredential, I get this error for Apple auth. [TypeError: undefined is not an object (evaluating 'credential._getIdTokenResponse')]
Here is my code.
const signInWithApple = () => {
const nonce = Math.random().toString(36).substring(2, 10);
return Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, nonce)
.then((hashedNonce) =>
AppleAuthentication.signInAsync({
requestedScopes: [
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
AppleAuthentication.AppleAuthenticationScope.EMAIL
],
nonce: hashedNonce
})
)
.then((appleCredential) => {
const { identityToken } = appleCredential;
const provider = new OAuthProvider('apple.com')
const credential = provider.credential({
idToken: identityToken,
rawNonce: nonce
});
return signInWithCredential(credential); // Line causing error
})
.catch((error) => {
console.log(error)
});
};

I found the error.
Instead of signInWithCredential(credential), I put signInWithCredential(auth,credential).
I also added a service ID in the firebase console.

Related

messaging().getToken() generates same device token for different devices

I got an issue with fcm tokens, they are identical for some devices (as you can see from screenshot). On internet it is said that they should be unique for each device, but it seems that in our case they are not. This is the way how I get fcm tokens from messaging library (react native firebase):
export const AppMaintainer = () => {
const fullname = useAppSelector(getMyFullName);
const photoUrl = useAppSelector(getPhotoUrl);
const userDocId: string = useAppSelector(getCurrentUserDocId);
const token: TokenOrProvider = useAppSelector(getCurrentStreamToken);
const dispatch = useAppDispatch();
useEffect(() => {
dispatch(actions.authStateChangeUser());
}, []);
const requestUserPermission = async () => {
const authStatus = await messaging().requestPermission();
const enabled =
authStatus === messaging.AuthorizationStatus.AUTHORIZED ||
authStatus === messaging.AuthorizationStatus.PROVISIONAL;
if (enabled) {
console.log('Authorization status:', authStatus);
const deviceToken = await getFcmToken();
try {
await firestore()
.collection('usersDescriptiveData')
.doc(userDocId)
.update({
deviceToken,
});
} catch (error: any) {
console.log('error in deviceToken update');
dispatch(
globalActions.setIsGlobalSnackbarVisible({message: error.message}),
);
}
}
};
const getFcmToken = async () => {
try {
const fcmToken = await messaging().getToken();
return fcmToken;
} catch (error) {
console.log('error in fcm', error);
}
};
useEffect(() => {
if (userDocId && photoUrl && token && fullname) {
requestUserPermission();
}
}, [userDocId, photoUrl, token, fullname]);
return (
<>
<NavigationContainer ref={navigationContainerRef}>
<RootNavigator />
</NavigationContainer>
<NetGlobalSnackbar />
</>
);
};
Could you please say what i am doing wrong?
Package.json:
"react-native": "0.69.6",
"#react-native-firebase/messaging": "12.9.3".
Additionally, I assume that these duplicated tokens are the reason why some users get notifications more then two times (but this is another story).
I tried calling the getFsmToken function again when deviceToken was already in use by another user, but it didnt help. Additionally, tried deleting and generating the deviceToken again, but it didnt help too. I expected this token to be unique for each device, but it is not, which means i am doing something wrong. FYI: i dont do it with browser, the app is available on stores and some users get the same token for their devices
Could anyone guide me with this?

TypeError: undefined is not an object (evaluating '_this.getFcmToken')

How to get fcm token from firebase in react-native . Currently I am using these packages
#react-native-firebase/app
#react-native-firebase/messaging
my code
const RegisterScreen = (props) => {
const [fcmToken, setfcmToken] = useState();
useEffect(() => {
messaging()
.getToken()
.then(token => {
return saveTokenToDatabase(token);
});
}, []);
async function saveTokenToDatabase(token) {
console.log(token)
}
}
I want to get fcm token from firebase when any user register in react native but it gives me that error
TypeError: undefined is not an object (evaluating '_this.getFcmToken')
I would recommend to rewrite the code like this:
const RegisterScreen = async (props) => {
const [fcmToken, setfcmToken] = useState();
useEffect(() => {
messaging()
.getToken()
.then((token) => {
return setfcmToken(token);
});
}, []);
async function saveTokenToDatabase(token) {
console.log(token);
}
useEffect(() => {
if (fcmToken) {
saveTokenToDatabase(fcmToken);
}
}, [fcmToken]);
};
From your error message it looks like you try to get the token from this. You either habe an issue with async/await where you try to get it before you set it or an issue with useEffect where you also coult try to get it before it is set to the state. I'm also not sure where to you want to use this in a react function. They don't have this.

Why is firebase cloud function invoked in react-native not logging output?

I have a firebase cloud function:
exports.copyImage = functions.region('us-central1').https.onCall(async (data, context) => {
const { auth } = context || {}
const { uid } = auth || {}
if (!uid) throw 'Unauthenticated'
const srcBucketName = <bucket-name>'
const destinationBucketName = '<bucket-name'
const { imageFile, archiveId, sessionId } = data
const srcFileName = `message-attachments/${imageFile}`
const destinationFileName = `archived-attachments/${uid}/${imageFile}`
console.log(`source path: ${srcFileName}\ndestination path: ${destinationFileName}`)
const storage = new Storage()
storage
.bucket(srcBucketName)
.file(srcFileName)
.copy(storage.bucket(destinationBucketName).file(destinationFileName))
.then(() => {
console.log(`COPY SUCCESS: gs://${destinationBucketName}/${destinationFileName}`)
})
.catch(err => console.error('COPY ERROR: ' + err))
})
and I have a react-native project (v61.5) using react-native-firebase (v5) which calls this function:
firebase.functions().httpsCallable('copyFile')({
imageFile: fileName,
archiveId: uid,
sessionId
})
.then(() => {
// copied file
const ref = firebase.storage()
.ref('archived-attachments')
.child(uid)
.child(fileName)
ref.getDownloadURL()
.then(url => {
// do more
})
.catch(err => alert(err.message))
})
.catch(err => {
// copy error
})
the problem is im not getting any log output in the functions console when executing this function. the functions been successfully deployed as well. Any advice?
Updating my comment in this answer as it solves the issue.
The issue occurred because Jim has been triggering a different function copyFile
instead of copyImage.
mismatch between the function name exports.copyImage vs httpsCallable('copyFile').
Updating the function name solved the issue!

Firebase Cloud Functions: Cannot pass the token retrieved from Realtime Database

I'm having issues in retrieving a token saved in realtime database using cloud function's admin.database(). There is only one token to read from the child.
Firebase Database structure
Here's my code in Index.js
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.sendNotification = functions.database
.ref('/Logs/{LogsID}')
.onWrite( (change, context) => {
const notificationSnapshot = change.after.val();
const status = notificationSnapshot.Status;
const time = notificationSnapshot.Time;
const payload = {
notification: {
title : status,
body : time
}
}
console.info(notificationSnapshot);
const pushToken = admin.database().ref('/Tokens').once('child_added').then( (data) => {
const tokenSnapshot = data.val();
const finaltoken = tokenSnapshot.token;
console.info(finaltoken);
})
// Need help down here.
admin.messaging().sendToDevice(finaltoken, payload)
.then( () => {
console.log('Notification sent');
})
.catch( () =>{
console.log('Notification failed');
})
return null;
});
finalToken shows the correct token in log as expected. Log Showing the token
But I'm getting error while I'm passing the same token to admin.messaging(). Console is logging 'Notification sent' but not receiving a notification.
ReferenceError: finaltoken is not defined
at exports.sendNotification.functions.database.ref.onWrite (/user_code/index.js:43:36)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-functions.js:135:20)
at /var/tmp/worker/worker.js:827:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
It works when I directly pass the token like,
var finalToken = 'ephrj1........kndji'
so the admin.messaging() works, only passing the token is not working.
I'm new to Cloud Functions and javascript, so any help is much appreciated.
Final token is being retrieved in callback / async function.
That means that when you add it to .sendToDevice() the token is undefined because the async function has not retrieved the token from the database... yet.
const pushToken = admin.database().ref('/Tokens').once('child_added').then( (data) => {
const tokenSnapshot = data.val();
const finaltoken = tokenSnapshot.token;
console.info(finaltoken);
admin.messaging().sendToDevice(finaltoken, payload)
.then( () => {
console.log('Notification sent');
})
.catch( () =>{
console.log('Notification failed');
})
// I moved admin.messaging above this bracket
})
// It used to be here
return null;
Try putting the admin.messaging code within the code block of (data) => {}
By doing this we ensure that whenever we call sendToDevice() the token is defined.

I can't replace the sk_test key with the sk_live key on Stripe using Firebase cloud functions

I have a React Native application, running on a firebase backend. I have integrated with Stripe. The token is created by the client, and the firebase cloud function creates the charge with that token. I have built the app and tested payments using the test keys in Stripe.
I have now replaced the test keys with the live keys.
The live public key is working in the React Native application, and is creating a token successfully.
here is the function for creating the token code in the React Native application
import Stripe from 'react-native-stripe-api';
async payByCard() {
const { user } = this.props;
const uid = user.uid;
const { number, exp_month, exp_year, cvc } = this.state;
this.setState({ loading: true });
const apiKey = 'pk_live_#######################';
const client = new Stripe(apiKey);
try {
const token = await client.createToken({
number,
exp_month,
exp_year,
cvc,
});
this.props.addToken({ token }, uid);
} catch (error) {
this.setState({ error: error.message, loading: false });
}
}
The firebase cloud functions, however, is still using the secret test key.
here is the loud function for creating a charge.
import * as functions from 'firebase-functions';
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const stripe = require('stripe')(functions.config().stripe.testkey)
export const stripeCharge = functions.database
.ref('/payments/{userUid}/{paymentUid}')
.onWrite((change, context) => {
const payment = change.after.val();
const userUid = context.params.userUid;
const paymentUid = context.params.paymentUid;
if (!payment || payment.charge || !payment.pendingBasket) return;
return admin.database()
.ref(`/users/${userUid}`)
.once('value')
.then(snapshot => {
return snapshot.val();
})
.then(customer => {
const amount = Number(payment.pendingBasket.total * 100).toFixed(0)
const idempotency_key = paymentUid;
const source = payment.token.id;
const currency = 'gbp';
const description = `Athalens ${customer.address.FirstName} ${customer.address.LastName} - ${customer.address.PostCode}`
const charge = {amount, currency, description, source};
return stripe.charges.create(charge, { idempotency_key });
}).catch((error) => {
console.log('error 1 =' + error.message);
admin.database()
.ref(`/payments/${userUid}/${paymentUid}/status`)
.set(error.message)
})
.then(charge => {
admin.database()
.ref(`/payments/${userUid}/${paymentUid}/charge`)
.set(charge)
if (charge.status === "succeeded") {
customerOrders(userUid, paymentUid)
photographerUid(userUid, paymentUid)
clearBasket(userUid)
confirmation(userUid, paymentUid);
} else {
decline(userUid, paymentUid)
}
}).catch((error) => {
console.log('error 2 =' + error.message);
})
})
The process I am doing to upload the Secret key to firebase:
1. Williams-MBP:~ williamgoodhew$ cd /Users/williamgoodhew/projects/athalens/athalens_server_code/basket/functions
2. Williams-MBP:functions williamgoodhew$ firebase functions:config:set stripe.token=“sk_live_#################”
3. Williams-MBP:functions williamgoodhew$ firebase deploy --only functions
When I test the live payment system, a token is created, but no charge is created. and I receive the following error in the cloud functions log:
No such token: tok_############; a similar object exists in live mode, but a test mode key was used to make this request.
I have got in contact with Firebase and it was a silly error my end.
In my cloud function, I had initialized my test key "
const stripe = require('stripe')(functions.config().stripe.testkey)
" instead of using "stripe.token".
I changed stripe.testkey to stripe.token.and everything worked out fine.

Resources