Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to protect firebase Cloud Function HTTP endpoint to allow only Firebase authenticated users?

People also ask

Does Firebase use HTTP requests?

Requests on your Firebase Hosting site can be proxied to specific HTTP functions. This also allows you to use your own custom domain with an HTTP function.

Are Firebase Functions secure?

Firebase gives direct access to Firestore from an app using the Firebase SDK, and that access is protected by security rules that you deploy to your project.


There is an official code sample for what you're trying to do. What it illustrates is how to set up your HTTPS function to require an Authorization header with the token that the client received during authentication. The function uses the firebase-admin library to verify the token.

Also, you can use "callable functions" to make a lot of this boilerplate easier, if your app is able to use Firebase client libraries.


As mentioned by @Doug, you can use firebase-admin to verify a token. I've set up a quick example:

exports.auth = functions.https.onRequest((req, res) => {
  cors(req, res, () => {
    const tokenId = req.get('Authorization').split('Bearer ')[1];
    
    return admin.auth().verifyIdToken(tokenId)
      .then((decoded) => res.status(200).send(decoded))
      .catch((err) => res.status(401).send(err));
  });
});

In the example above, I've also enabled CORS, but that's optional. First, you get the Authorization header and find out the token.

Then, you can use firebase-admin to verify that token. You'll get the decoded information for that user in the response. Otherwise, if the token isn't valid, it'll throw an error.


As also mentioned by @Doug, you can use Callable Functions in order to exclude some boilerplate code from your client and your server.

Example callable function:

export const getData = functions.https.onCall((data, context) => {
  // verify Firebase Auth ID token
  if (!context.auth) {
    return { message: 'Authentication Required!', code: 401 };
  }

  // do your things..
  const uid = context.auth.uid;
  const query = data.query;

  return { message: 'Some Data', code: 400 };
});

It can be invoked directly from you client like so:

firebase.functions().httpsCallable('getData')({query}).then(result => console.log(result));

The above methods authenticate the user using logic inside the function, so the function must be still be invoked to do the checking.

That's a totally fine method, but for the sake of comprehensivity, there is an alternative:

You can set a function to be "private" so that it can't be invoked except by registered users (you decide on permissions). In this case, unauthenticated requests are denied outside the context of the function, and the function is not invoked at all.

Here are references to (a) Configuring functions as public/private, and then (b) authenticating end-users to your functions.

Note that the docs above are for Google Cloud Platform, and indeed, this works because every Firebase project is also a GCP project. A related caveat with this method is that, as of writing, it only works with Google-account based authentication.