how to initialize firebase admin SDK in nodejs - node.js

I am try to initialize firebase admin SDK in my project but it is not working. I intend using it in my next js API for admin backend
import {
initializeApp,
applicationDefault,
cert,
} from "firebase-admin/app";
import {
getFirestore,
Timestamp,
FieldValue,
} from "firebase-admin/firestore";
import serviceAccount from "../secret.json";
const app = initializeApp({
credential: cert(serviceAccount),
});
export default app.getFirestore();

Related

How to properly Organize Firebase Functions in Groups?

I am following This Guide to create a Functions project with multiple function files in NodeJS. while this is a good base, it does not show how to properly initiate a firebase app by using const app = admin.initializeApp() in a way that could be reused across the different files. my initial thought was to add the following in index.ts and import app as needed, but this raises a Maximum call stack size exceeded error.
import admin = require('firebase-admin');
export const app = admin.initializeApp();
While searching online I could only find some older posts that don't apply to current versions. can anyone provide a guideline for this?
This looks like a circular dependency issue. You need to initialize Firebase Admin only once at the beginning of index.ts and import other services as needed in other files as shown below:
// index.ts
// Don't export anything from this file.
import { initializeApp } from "firebase-admin/app";
initializeApp({
databaseURL: "<DB_URL>",
storageBucket: "<BUCKET>.appspot.com",
});
export * from "./metric";
// metric.ts
import { https } from "firebase-functions/v1";
import { getFirestore } from "firebase-admin/firestore";
const db = getFirestore();
export const test = https.onRequest(async (req, res) => {
const metricData = await db.collection("metrics").get();
res.json(metricData.docs.map((doc) => doc.data()));
});

How to use Firebase Cloud Functions with the new modular Firestore API?

I have upgraded my Firebase v8 project to v9. The web application now uses the modular SDK with the new functional API for Firestore.
In this project I use Firebase Functions. There I have upgraded to firebase-admin 11.0.0. But it seams it does not provide the new functional API for Firestore.
const { initializeApp } = require('firebase-admin/app');
const app = initializeApp();
import { getFirestore } from "firebase/firestore";
const db = getFirestore(app);
This throws:
TypeError: Cannot read properties of undefined (reading 'getProvider')
at Object._getProvider (/p/happygast/node_modules/#firebase/app/src/internal.ts:110:6)
at Object.getFirestore (/p/happygast/node_modules/#firebase/firestore/src/api/database.ts:185:10)
Now I am not sure if I am doing something wrong? Or is there no functional Firestore API for Cloud Functions?
In essence: Is firebase-admin/app compatible with firebase/firestore? Or: How do I initialize and use firebase/firestore in Firebase Cloud Functions?
You are importing initializeApp() from the Firebase Admin SDK but getFirestore() from the Firebase Client SDK and then passing an instance of Admin SDK in it that's invalid. Instead, you should import Firestore from the Admin SDK itself as shown below:
const { initializeApp } = require('firebase-admin/app');
const { getFirestore } = require('firebase-admin/firestore'); // not firebase/firestore
// Initialize by ADC or another service account
const app = initializeApp();
const db = getFirestore(app);
If you want to use the client SDK, then you'll have to initialise the Firebase instance using the client SDK itself:
const { initializeApp } = require('firebase/app');
const { getFirestore } = require('firebase/firestore');
// use the web config that can be found in Firebase console
const clientApp = initializeApp({ ...config });
cpmst db = getFirestore(clientApp);

How to access admin firestore using firebase admin SDK?

I am working on an application, where it uses Next.js and Firebase.
I need to implement server-side authentication. Firebase allows connecting the server using Firebase Admin SDK.
const admin = require("firebase-admin");
const serviceAccount = require("../../../../3-firebase/service-account-key/service-account-file.json");
try {
admin.initializeApp({
credential: admin.credential.cert({
client_email: process.env.FIREBASE_CLIENT_EMAIL,
private_key: process.env.FIREBASE_PRIVATE_KEY,
project_id: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
}),
});
console.log("Initialized.");
} catch (error) {
if (!/already exists/u.test(error.message)) {
console.error("Firebase admin initialization error", error.stack);
}
}
const db = admin.firestore();
export { db };
I installed the firebase-admin package using NPM and I setup firebase admin SDK using the above code by creating a separate file called "firebase-admin.js"
import { initializeApp } from "firebase/app";
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
};
const defaultApp = initializeApp(firebaseConfig);
export default defaultApp;
The above code is the default firebase application setup in a separate file called "firebase.js"
The problem I encountered is I am not able to access the admin firestore. However, I can able to access the default firestore.
What I observed is admin SDK is able to initialize using the credentials (private key). But I don't know why I can't access admin firestore. I mean when i use admin firestore the console gives error of 500 (internal server error)
Here is the error message, when I try to use admin.firestore()
{"error":{"code":"invalid-argument","name":"FirebaseError"}}
versions I am using
"firebase": "^9.6.6",
"firebase-admin": "^10.0.2",
Timely help is much needed
You're importing the initializeApp method from the Firebase Javascript SDK. You should be importing from the Firebase Admin SDK.
import { initializeApp } from "firebase/app";
vs.
import { initializeApp } from "firebase-admin/app";
Using firebase-admin v10.0.2 I was able to successfully access the db adding this in my config.js file, similar to your firebase.js file.
const ServiceAccount = require('../superSecretServiceKeyFile.json');
const app = initializeApp(ServiceAccount);
const { getFirestore } = require('firebase-admin/firestore');
const db = getFirestore(app);

How to configure firebase-admin-sdk for `verifyIdToken` to pass?

I try to use Firebase in my application. The frontend logs the user in using the Web SDK, without any backend. Later, I would like to call some backend APIs. For this reason, I pass the idToken to the backend and try to validate the user as described in the Firebase docs.
When I do the above flow locally using the Firebase Emulator everything works as expected.
When I switch off the Emulator the idToken validation fails with
{
errorInfo: {
code: 'auth/argument-error',
message: 'Firebase ID token has invalid signature. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token.'
},
codePrefix: 'auth'
}
I created a Google hosted Firebase function to check if I can get the idToken validated there. The above setup works when the validation happens within the Google infrastructure.
Based on the above, I think the issue is in my FirebaseApp setup in the API. What that issue might be?
This is my setup.
I define 3 environment variables:
FIREBASE_DB_URL=https://<project-id>.firebaseio.com
FIREBASE_PROJECT_ID=<project-id>
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
I checked and cat $GOOGLE_APPLICATION_CREDENTIALS prints the correct file.
I initialize Firebase in the API with
import admin from "firebase-admin";
if(admin.apps.length == 0) {
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: process.env.FIREBASE_DB_URL,
projectId: process.env.FIREBASE_PROJECT_ID,
});
console.log('Firebase initialized')
} else {
console.warn('Firebase already initialized')
}
and this is the validating code
import { DecodedIdToken } from 'firebase-admin/lib/auth/token-verifier';
import { getAuth } from 'firebase-admin/auth';
import './initializeFirebase';
export default async function needsLoggedInUser(idToken: string): Promise<DecodedIdToken|false> {
try {
return await getAuth().verifyIdToken(idToken)
} catch(err) {
console.error(err)
return false
}
}
I use the above in a NextJS API code as
import { NextApiRequest, NextApiResponse } from 'next'
import { getDatabase } from 'firebase-admin/database';
import 'services/backend/initializeFirebase';
import needsLoggedInUser from 'services/backend/needsLoggedInUser';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
// As an admin, the app has access to read and write all data, regardless of Security Rules
const decodedToken = await needsLoggedInUser(req.body.user)
if(!decodedToken) {
return res.status(403).send("403 Forbidden")
}
/// ... rest of the API
}

Firebase database isn't starting

I am a newbie in JavaScript. Recently I have installed firebase admin and kept the code in global scope, database.js. Like this.
import app from 'firebase-admin';
import firebase_key from './firebase_key.js';
app.initializeApp({
credential: app.credential.cert(firebase_key),
databaseURL: "https://study-boss-681fa-default-rtdb.firebaseio.com"
});
console.log('database started');
export default app.database();
Now I want to access this database from my service class. My serice class is
import { getDatabase} from "firebase-admin/database";
const database = getDatabase();
This service class code is throwing the following error.
FirebaseAppError: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.
If you are just using getDatabase() directly then there's a high chance that it's being access before your initializeApp is executed. I would recommend initializing all Firebase services in a single file and importing them wherever required as shown below:
import { initializeApp } from 'firebase-admin/app';
import { getDatabase } from 'firebase-admin/database';
import firebase_key from './firebase_key.js';
const app = initializeApp({
credential: app.credential.cert(firebase_key),
databaseURL: "https://study-boss-681fa-default-rtdb.firebaseio.com"
});
const database = getDatabase(app);
console.log('database started');
export { database };
Now you can import { database } from "..path/to/firebase.js" wherever required.

Resources