Home > Back-end >  Make http cloud function executable only by the project owner
Make http cloud function executable only by the project owner

Time:05-29

I am using http cloud function ( https://firebase.google.com/docs/functions/http-events ) to write documents to a firestore collection:

exports.hello = functions.https.onRequest(
  (req: { query: { name: string } }, res: { send: (arg0: string) => void }) => {
    console.log(req.query.name);
    var name = req.query.name || 'unknown';
    res.send('hello'   name);
    admin
      .firestore()
      .collection('ulala')
      .doc()
      .set({ token: 'asd' }, { merge: true });
  }
);

this is a test. The problem is that, once you deploy and get the link to the function, it is executable by everyone. I would like instead that only I (project owner) can use it . Is it possible to do this?

CodePudding user response:

One possible solution is to restrict your HTTPS Cloud Function to only a specific "Admin" user of your app.

There is an official Cloud Function sample which shows how to restrict an HTTPS Function to only the Firebase users of the app/Firebase project: Authorized HTTPS Endpoint sample.

You need to adapt it to check if the user is the Admin user. For example by checking the userID in the try/catch block at line 60 of the index.js file (untested).

try {
    const decodedIdToken = await admin.auth().verifyIdToken(idToken);
    if (decodedToken.uid !== "<the admin user uid>") {
        throw new Error("Wrong user");
    } else {
        req.user = decodedIdToken; 
        next();                
    }
    return;
} catch (error) {
    functions.logger.error('Error while verifying Firebase ID token:', error);
    res.status(403).send('Unauthorized');
    return;
}

The two drawbacks of this approach are:

  • Your Admin user needs to be declared as a Firebase project user in the Authentication service
  • You hard code the Admin userID in your Cloud Function (you could use the Google Cloud Secret Manager service to securely store it as a configuration value, see the doc).

IMPORTANT SIDE NOTE:

In your Cloud Function you call the send() method before the asynchronous work is complete:

res.send('hello'   name);
admin
  .firestore()
  .collection('ulala')
  .doc()
  .set({ token: 'asd' }, { merge: true });

By calling the send() method, you actually terminate the Cloud Function, indicating to the Cloud Functions instance running your function that it can shut down. Therefore in the majority of the cases the asynchronous set() operation will not be executed.

You need to do as follows:

admin
  .firestore()
  .collection('ulala')
  .doc()
  .set({ token: 'asd' }, { merge: true })
.then(() => {
   res.send('hello'   name);
})

I would suggest you watch the 3 videos about "JavaScript Promises" from the Firebase video series as well as read this page of the documentation which explain this key point.

  • Related