Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The incoming JSON object does not contain a client_email field

I'm trying to create a firebase cloud function. So I would to run my firebase cloud function locally. But it do not work how to setup authentication.

I have installed firebase tools : https://firebase.google.com/docs/functions/local-emulator I've runned the command firebase login, so now I'm logged. Then I've created my json key with this tutorial : https://cloud.google.com/docs/authentication/getting-started Now if I type echo $GOOGLE_APPLICATION_CREDENTIALS the result is /home/$USER/.google/****.json which contain

"project_id","private_key_id","private_key","client_email", "client_id",  "auth_uri", "token_uri", "auth_provider_x509_cert_url", "client_x509_cert_url"

Also I've tried to install the full google cloud sdk and I runned : gcloud auth application-default login but no success.

Npm package versions :

"firebase-functions":"3.0.2"
"firebase-admin": "8.2.0"

I think I've provided enought information but feel free to ask me more if you want.

const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
const app = express();
app.get("/", async (req, res) => {
admin.firestore().collection('something').get().then((collection) =>
    return res.send({"count": collection.docs.length, "status": 200});
});
exports.exports = functions.https.onRequest(app);

the code is not important, the most important thing is that even I've done all theses steps, when I emulate my firebase locally with firebase serve and I trigger a function, I have this error : Error: The incoming JSON object does not contain a client_email field

I can ensure you the json file contains client_email field.

Can you help me to authenticate with google ?

Thanks for your help.

like image 300
Shining Avatar asked Jun 27 '19 10:06

Shining


3 Answers

I had a similar problem. It's likely a bug in version 7.0.2 of firebase-tools. I rolled back to version 7.0.0 and it works now.

So the temporary solution is:

npm i [email protected] -g  
like image 168
tomexx Avatar answered Oct 18 '22 20:10

tomexx


In short:

admin.initializeApp({ credential: admin.credential.applicationDefault() });

See docs for admin.credential.applicationDefault()

Update: Note that this is only recommended for testing/experimenting:

This strategy is useful when testing and experimenting, but can make it hard to tell which credentials your application is using. We recommend explicitly specifying which credentials the application should use, ... Source

A little more info

I had the same when trying to call a firebase function locally which tries to update some documents in firestore database in batch. (Didn't test without batch).

To start calling firebase functions locally, I use:

firebase function:shell

As you probably know, this lists the available functions for your project.

I called my function and got the following error callstack:

Unhandled error Error: The incoming JSON object does not contain a client_email field
>      at JWT.fromJSON (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-auth-library\build\src\auth\jwtclient.js:165:19)
>      at GoogleAuth.fromJSON (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-auth-library\build\src\auth\googleauth.js:294:16)
>      at GoogleAuth.getClient (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-auth-library\build\src\auth\googleauth.js:476:52)
>      at GrpcClient._getCredentials (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-gax\build\src\grpc.js:107:40)
>      at GrpcClient.createStub (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\google-gax\build\src\grpc.js:223:34)
>      at new FirestoreClient (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\v1\firestore_client.js:128:39)
>      at ClientPool.Firestore._clientPool.pool_1.ClientPool [as clientFactory] (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\index.js:315:26)
>      at ClientPool.acquire (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\pool.js:61:35)
>      at ClientPool.run (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\pool.js:114:29)
>      at Firestore.readStream (D:\thdk\Projects\timesheets\functions\node_modules\firebase-admin\node_modules\@google-cloud\firestore\build\src\index.js:995:26)

RESPONSE RECEIVED FROM FUNCTION: 500, {
  "error": {
    "status": "INTERNAL",
    "message": "INTERNAL"
  }
}

I was running my function locally using the command line: firebase functions:shell

I was using this code:

// Reference report in Firestore
const db = admin.firestore();

admin.initializeApp();

export const performMyCallableFirebaseFunction = (db, { from, to }) => {
    return db.collection("collectionName").where("prop", "==", from).limit(500).get().then(snapshot => {
        if (snapshot.empty) return new Promise(resolve => resolve(`No docs found with prop: ${from}`));

        const batch = db.batch();
        snapshot.forEach(doc => batch.update(doc.ref, { prop: to }));

        return batch.commit();
    });
};
exports.myCallableFirebaseFunction = functions.https.onCall(data => performMyCallableFirebaseFunction(db, data.from, data.to));

I changed the line

admin.initializeApp();

to

admin.initializeApp({ credential: admin.credential.applicationDefault() });

and now I was able to call my function locally using:

firebase functions:shell
firebase > myCallableFirebaseFunction({from: "foo", to: "bar"})

See docs for admin.credential.applicationDefault()

like image 36
ThdK Avatar answered Oct 18 '22 20:10

ThdK


You probably need to set up the Firebase Admin SDK to use the Firebase emulator. You can do it by passing a credential property when calling the admin.initializeApp() method:

const serviceAccount = require('../serviceAccount.json');

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount),
});

You can download your service account JSON file in the Firebase console:

  • Click on the "settings" icon;
  • Go to "Users and permissions";
  • Click on the link where it says "N service accounts also have access to this project";
  • Click on the "Generate new private key" button.
like image 4
Will Avatar answered Oct 18 '22 22:10

Will