The incoming JSON object does not contain a client_email field
Asked Answered
C

7

23

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.

Canzonet answered 27/6, 2019 at 10:53 Comment(2)
Man, I've been working on my local machine for 1 year with no problems, and now I'm getting this error from the last 24 hours. So, it should be a temporal issue.Lumbard
I have the same issueDupuy
D
18

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  
Dupuy answered 28/6, 2019 at 11:44 Comment(3)
7.0.1 also works fine. 7.0.2 throws this error for me every time when using functions:shellAllain
Downgrading to [email protected] worked for me. I suppose the bug is in the latest version of firebase-tools.Platinumblond
Hopefully next info is useful for someone. After downgrading to 7.0.0 I got the error Getting metadata from plugin failed with error: invalid_grant which I fixed deleting the file ~/.config/gcloud/application_default_credentials.json (macOS) and recreating it by running ` gcloud auth application-default login`.Speechmaking
C
12

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()

Culdesac answered 4/7, 2019 at 8:43 Comment(0)
N
4

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.
Network answered 27/6, 2019 at 20:25 Comment(1)
I followed this from the Firebase Admin SDK page and it worked. Thanks.Giannini
I
3

Here is how I've solved the problem after struggling couple of hours:

Short answer:

Create Firebase-adminsdk key

How to do it:

  • Go to Google-cloud-platform > Service accounts https://console.cloud.google.com/iam-admin/serviceaccounts/

  • Select your project

  • Select your firebase-admin-sdk looks like firebase-adminsdk-u4k3i@example..
  • Enable edit mode
  • Create key and select JSON
  • You get the option to download a .json. Which has ProjectID, PrivateKey and ClientEmail in it
  • use the information like this where you initialize your app:
// Providing a service account object inline
admin.initializeApp({
    credential: admin.credential.cert({
        projectId: "<PROJECT_ID>",
        clientEmail: "foo@<PROJECT_ID>.iam.gserviceaccount.com",
        privateKey: "-----BEGIN PRIVATE KEY-----<KEY>-----END PRIVATE KEY-----\n"
    })
});
Ikey answered 16/7, 2019 at 20:38 Comment(0)
E
2

Once you have created a Firebase project, you can initialize the SDK with an authorization strategy that combines your service account file together with Google Application Default Credentials.

To authenticate a service account and authorize it to access Firebase services, you must generate a private key file in JSON format.

To generate a private key file for your service account:

  1. In the Firebase console, open Settings > Service Accounts.

  2. Click Generate New Private Key, then confirm by clicking Generate Key.

  3. Securely store the JSON file containing the key.

Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the file path of the JSON file that contains your service account key. This variable only applies to your current shell session, so if you open a new session, set the variable again.

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"

https://firebase.google.com/docs/admin/setup?authuser=3

Exobiology answered 28/6, 2019 at 11:49 Comment(0)
S
0

I was getting this error when running firebase emulators:start.

As per the investigation from this bug: https://github.com/firebase/firebase-tools/issues/1451, it seems that this is an issue with referencing the app directly instead of via the admin module.

i.e. this causes the error:

const app = admin.initializeApp();
const firestore = app.firestore();

but this does not:

admin.initializeApp();
const firestore = admin.firestore();

However for the original question, you're using admin.firestore() so that wouldn't be the problem. It seems that admin.initializeApp() is never called. Perhaps that could be the cause of your issue?

Sufferable answered 2/7, 2019 at 15:46 Comment(0)
T
0

I fixed this error by putting the code inside the setTimeOut() in Javascript. You have to call the firebase function inside the setTimeout() and add some delay for 1-2 seconds.

Telex answered 30/3, 2023 at 11:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.