I m getting Error while invoked function.
I m using LsignInWithEmailAndPassword Method.Any Special Configuration is Require?
const functions = require('firebase-functions');
const firebase=require('firebase-admin');
firebase.initializeApp(functions.config().firebase);
exports.login = functions.https.onRequest((request, response) => {
var data = {
email : 'demo#gmail.com',
password : 'demo123'
};
var auth = null;
firebase
.auth()
.signInWithEmailAndPassword(data.email, data.password)
.then( function(user){
response.send("Authenticated successfully with payload");
// console.log("Authenticated successfully with payload:", user);
auth = user;
})
.catch(function(error){
response.send("Login Failed!");
// console.log("Login Failed!", error);
});
// response.send("Hello from Firebase!");
});
When you call firebase.auth() from the Admin SDK, you're getting an object of type Auth. As you can see from the API docs, it doesn't have a method called signInWithEmailAndPassword.
It seems you're mixing up the javascript client SDK with the Admin SDK. There's no reason to use the client SDK in Cloud Functions. It's supposed to be used in the browser only, since signing in only makes sense on the device that the user is actually using.
signInWithEmailAndPassword is only available in a browser environment. To get access to who made a particular request, you can use firebase.auth().getToken to get a JWT token, and send that along to your cloud function endpoint. Then from there you can call verifyIdToken to get the uid of whoever made the request.
Related
I am using Firebase Cloud Functions with Express and Firebase Hosting to serve my multi-page site. I have successfully implemented server-side cookies as explained here and as implemented below:
function verifyLogin(request, response, next) {
const sessionCookie = request.cookies.__session || '';
firebase.auth().verifySessionCookie(sessionCookie, true /** checkRevoked */ )
.then((decodedClaims) => {
//serve content for user
return next();
}).catch(error => {
// Session cookie is unavailable or invalid. Force user to log in.
console.log(error);
response.redirect('/login');
return;
});
}
app.get('/', verifyLogin, (request, response) => {
var page_title = "Home";
response.render('index', {
page_title,
});
});
I am using the Firebase Web SDK (JavaScript) to access the Firebase Cloud Firestore. In order to do this, I need to get the idToken on the client side for the currently-logged-in user, like so:
firebase.auth().onAuthStateChanged(firebaseUser => {
if (firebaseUser) {
firebase.auth().currentUser.getIdTokenResult()
.then((idTokenResult) => {
// Access the Firebase Cloud Firestore here
});
}
});
This seems redundant to me, since I already know which user is signed in via my server cookie, but how else can I get the idToken without another call to Firebase Auth?
Is there a way to extrapolate it from my session cookie somehow and pass it to my client from my cloud function as a variable?
Or is there another way to look at this philosophically that I am overlooking?
In the same way you can listen to user sign-in state changes using onAuthStateChanged(), you can also listen to user ID token changes using onIdTokenChanged(). You will only need to use a new token when the observer you attach shows that a new one appears (for example, when it's refreshed every hour by the SDK).
I am calling a simple firebase function from a web app I get an INTERNAL error. Can someone please suggest where I could be going wrong.
I have seen similar questions but they don't answer the issue I am facing.
I can confirm that the function has been deployed to the firebase.
By pasting the below link in the browser I get a response.
https://us-central1-cureme-dac13.cloudfunctions.net/helloWorld
index.js file has the code (Firebase cloud functions are defined in index.js)
const functions = require('firebase-functions');
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});
webApp.js has the below code (Client/Website)
var messageA = firebase.functions().httpsCallable('helloWorld');
messageA().then(function(result) {
console.log("resultFromFirebaseFunctionCall: "+result)
}).catch(function(error) {
// Getting the Error details.
var code = error.code;
var message = error.message;
var details = error.details;
// ...
console.log("error.message: "+error.message+" error.code: "+error.code+" error.details: "+error.details)
// Prints: error.message: INTERNAL error.code: internal error.details: undefined
});
You are mixing up Callable Cloud Functions and HTTPS Cloud Functions.
By doing
exports.helloWorld = functions.https.onRequest(...)
you define an HTTPS Cloud Function,
but by doing
var messageA = firebase.functions().httpsCallable('helloWorld');
messageA().then(function(result) {...});
in your client/front-end, you actually call a Callable Cloud Function.
You should either change your Cloud Function to a Callable one, or call/invoque the helloWorld HTTPS Cloud Function by sending an HTTP GET Request to the Cloud Function URL (Similarly to the way you did in your browser by "pasting the https://us-central1-cureme-dac13.cloudfunctions.net/helloWorld link in the browser").
For example, by using the Axios library, you would do:
axios.get('https://us-central1-cureme-dac13.cloudfunctions.net/helloWorld')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
I'm working towards implementing push notifications that appear on change to a firebase firestore document. I'm using the react-native-firebase module. My google cloud function listens for changes to the firestore and then sends messages via firebase-admin.
google's reference says you can specify a single device to message with:
// This registration token comes from the client FCM SDKs.
var registrationToken = 'YOUR_REGISTRATION_TOKEN';
var message = {
data: {
score: '850',
time: '2:45'
},
token: registrationToken
};
// Send a message to the device corresponding to the provided
// registration token.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
client-side in my react-native app I get a token using react-native-firebase:
function getToken() {
let fcmToken = await AsyncStorage.getItem("fcmToken");
if (!fcmToken) {
fcmToken = await firebase.messaging().getToken();
if (fcmToken) {
await AsyncStorage.setItem("fcmToken", fcmToken);
}
}
}
Do I have to store the google cloud messaging token somewhere other than async storage or is there a way to access it as is, inside my google cloud function? It seems like I should be storing the auth token inside firestore and accessing firestore with cloud functions. is this the best way to do this?
You don't need AsyncStorage to access the token, it is available right from fcmToken = await firebase.messaging().getToken(); in your code.
From there you can either send it to a callback Cloud Function with something like:
var sendMessage = firebase.functions().httpsCallable('sendMessage');
addMessage({ token: fcmToken }).then(function(result) {
// ...
});
This is based on the example in the documentation here. You can then use this value in your Cloud Functions code to send a message by calling the FCM API through the Admin SDK.
Or store it in a database, such as Cloud Firestore with something like this:
db.collection("tokens").add(docData).then(function() {
console.log("Token successfully written to database!");
});
Which is based on the example in the documentation here. You can then read this value from the database in your Cloud Function and use it to again send a message by calling the FCM API through the Admin SDK.
I am using the Node.js Admin SDK within a Cloud Function for Firebase and I want to call the admin.auth().getUserByEmail() method.
Since I'm using a Cloud Function I read here that I only need to call admin.initializeApp(functions.config().firebase); which you can see below I've done.
However, when I call the getUserByEmail() (only tested locally) I get the following error:
'No Firebase project was found for the provided credential.'
Here's my index.js
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.hello = functions.https.onRequest(function (req, resp) {
var from = req.body.sender;
admin.auth().getUserByEmail(from)
.then(function (userRecord) {
// See the UserRecord reference doc for the contents of userRecord.
console.log("Successfully fetched user data:", userRecord.toJSON());
})
.catch(function (error) {
console.log("Error fetching user data:", error);
})
});
Has anyone got any experience of this and can tell me what I'm doing wrong?
The admin sdk won't get proper config json if you are using localy(in google cloud functions emulator). You have to use your service account json obtained from firebase console.
But if you have deployed it, your method will work just fine.
Is there a way to check if a user is firebase-authorized before triggering a cloud function? (Or within the function)
Yes. You will need to send the Firebase ID token along with the request (for example in the Authorization header of an AJAX request), then verify it using the Firebase Admin SDK. There is an in-depth example in the Cloud Functions for Firebase samples repository. It looks something like this (made shorter for SO post):
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')();
const validateFirebaseIdToken = (req, res, next) => {
cors(req, res, () => {
const idToken = req.headers.authorization.split('Bearer ')[1];
admin.auth().verifyIdToken(idToken).then(decodedIdToken => {
console.log('ID Token correctly decoded', decodedIdToken);
req.user = decodedIdToken;
next();
}).catch(error => {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
});
});
};
exports.myFn = functions.https.onRequest((req, res) => {
validateFirebaseIdToken(req, res, () => {
// now you know they're authorized and `req.user` has info about them
});
});
Since the question asks for auth-based access (1) within, or (2) before a function, here's an method for the "before" case: >
Since every Firebase Project is also a Google Cloud Project -- and GCP allows for "private" functions, you can set project-wide or per-function permissions outside the function(s), so that only authenticated users can cause the function to fire.
Unauthorized users will be rejected before function invocation, even if they try to hit the endpoint.
Here's documentation on setting permissions and authenticating users. As of writing, I believe using this method requires users to have a Google account to authenticate.