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);
})
Related
I have a firebase cloud function running locally. Its implemented like this
exports.verifyApp = functions.https.onRequest((req, res) => {
const {ref} = req.query;
// some business logic
if( ref === "123") return res.status(200).json({message: "success"});
return res.status(400).json({ error: "invalid-argument", message: "ref not provided" });
})
On frontend I am calling the cloud function like this
import {
getFunctions,
httpsCallableFromURL,
} from "firebase/functions";
const verifyClaim = httpsCallableFromURL(
getFunctions(),
"http://localhost:5001/{placeholder}/us-central1/verifyApp?ref=23"
);
verifyClaim()
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error.code, error.message);
});
I am not able to read/parse the custom error message being sent from the function. The .catch block only prints generic firebase error code and message i.e invalid-argument and internal. I can see the response in network tab though but .catch never seems to pick up the custom error message I am sending from cloud function.
You are mixing up Callable Cloud Functions and HTTP Cloud Functions.
You Cloud Function code corresponds to an HTTP one (functions.https.onRequest(...)) but the code in your front-end calls a Callable one (const verifyClaim = httpsCallableFromURL(...)).
You should adapt one or the other. It's difficult to advise which one to adapt with the few details shared in your answer.
Have deployed a few firebase functions (according to docs)
firebase init
Changed the code to something like
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.getUsers = functions
.region('europe-west1')
.https.onRequest((req, res) => {
admin.firestore().collection('users').get().then(data => {
const users = data.map(user => user.data());
return res.json(users);
}).catch(err => console.error(err));
});
exports.helloWorld = functions.https.onRequest((req, res) => {
res.status(200).send('Hello, World!');
});
Deployed it.
firebase deploy
And as an end result both of the functions return
Error: Forbidden Your client does not have permission to get URL
/getUsers from this server.
Error: Forbidden Your client does not have permission to get URL
/helloWorld from this server.
In the firebase admin console I see that functions exist, and they are there, and I am using same exact urls that the terminal gave me & are on the firebase admin console.
Any ideas?
PS. Located in Estonia.
Alright,
To solve this issue I had to use my brain and check the dashboard for cloud functions. Cloud functions do not return a 500 error unlike most common APIs, instead inside of the dashboard I found out that:
TypeError: data.map is not a function
admin.firestore.collection.get.then.data ( /user_code/index.js:10 )
Meaning my 'application' was crashing, oddly enough it was giving me a 403 error.
For good measure I also followed this:
Firebase cloud function "Your client does not have permission to get URL /200 from this server"
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.
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.