Taio
Taio

Reputation: 3734

retrieve secret firebase service account json

I have this code in nextjs that is supposed to check if a token is valid then sign in the user.

const firebaseAdmin = require("firebase-admin");
const serviceAccount = require ('../secret.json');

export const verifyIdToken = async (token) => {
  if (!firebaseAdmin.apps.length) {
   
    firebaseAdmin.initializeApp({
      // credential: firebaseAdmin.credential.cert(serviceAccount),
      credential: firebaseAdmin.credential.applicationDefault(),
      databaseURL: "rtdb.firebaseio.com",
    });
  }

  return await firebaseAdmin
    .auth()
    .verifyIdToken(token)
    .catch((error) => {
      throw error;
    });


};

I have the windows environment variables set as firebase recommends and switched to using the applicationDefault() since as I understand,

ADC can automatically find your credentials

Problem is the application works only locally. When I deploy the website, the token is not verified and creates errors. I am serving the NextJs app through a cloud function. How can I solve this. The error is

auth/invalid-credential
Must initialize app with a cert credential or set your Firebase project
ID as the GOOGLE_CLOUD_PROJECT environment variable to call verifyIdToken().

What the app is supposed to do is do a check server side to determine if a token is valid. As below

export async function getServerSideProps(ctx) {
  try {
    const cookies = nookies.get(ctx);
    const token = await verifyIdToken(cookies.token);

    // the user is authenticated!
    const { uid, email } = token;

    
    return {
      props: {
        userData: {
          email: email,
          uid: uid,
          
        },
      },
    };
  } catch (err) {
    console.log(err.code)
    console.log(err.message)
    return { props: {
    } };
  }
}

Upvotes: 0

Views: 2632

Answers (2)

Pamela Chup
Pamela Chup

Reputation: 161

The auth/invalid-credential error message means that the Admin SDK needs to be initialized, as we can see in the Official Documentation.

The credential used to authenticate the Admin SDKs cannot be used to perform the desired action. Certain Authentication methods such as createCustomToken() and verifyIdToken() require the SDK to be initialized with a certificate credential as opposed to a refresh token or Application Default credential.

And for the ID token verification, a project ID is required. The Firebase Admin SDK attempts to obtain a project ID via one of the following methods:

  • If the SDK was initialized with an explicit projectId app option, the SDK uses the value of that option.
  • If the SDK was initialized with service account credentials, the SDK uses the project_id field of the service account JSON object.
  • If the GOOGLE_CLOUD_PROJECT environment variable is set, the SDK uses its value as the project ID. This environment variable is available for code running on Google infrastructure such as App Engine and Compute Engine.

So, we can initialize the Admin SDK with a service (and fulfill the second option); but, the first thing to do is 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 you can do the following:

  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.

Once you have your JSON file, you can set a environment variable to hold your private key.

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

And then, use it in your code like this:

admin.initializeApp({
    credential: admin.credential.applicationDefault(),
    databaseURL: 'https://<DATABASE_NAME>.firebaseio.com'
});

Upvotes: 2

Taio
Taio

Reputation: 3734

In the end I downloaded Gcloud tool and setting the GOOGLE_APPLICATION_CREDENTIALS environment variable from the tool worked. The function could then work with credential: firebaseAdmin.credential.applicationDefault(),

Upvotes: 0

Related Questions