Firebase getAuth() throws error getProvider of undefined but can access database

Viewed 4273

I have the following code running on a Node server.

import admin from 'firebase-admin';
import {getAuth} from 'firebase/auth';
class MyFirebase {

   constructor() {
     console.log("MyFirebase Constructor");
     this.firebaseApp = admin.initializeApp({
          credential: admin.credential.cert("PATH_TO_CERT/cert.json"),
          databaseURL: "https://DATABASE_URL",
      });
      
      console.log("App name="+firebaseApp.name);

      this.defaultAuth = getAuth(firebaseApp);
      this.database = this.firebaseApp.database();
      // database ref code here...
   }
}

and it throws the following error:

return app.container.getProvider(name); TypeError: Cannot read property 'getProvider' of undefined

If I remove "firebaseApp" from the getAuth(..) call I get this error:

No Firebase app '[DEFAULT'] has been created - call Firebase App.initializeApp() (app/no-app)

However the "console.log("App Name...")" line produces:

App name=[DEFAULT]

So clearly a DEFAULT app has been created. Additionally if I remove the "getAuth..." call the database calls pulling data from the realtime database below it work just fine, which seem to imply the authentication worked properly because I can access data from the database.

What the heck is going on?

2 Answers

You are confusing Firebase Admin SDK (Node.js) with Firebase Javascript SDK. The former is for the back-end, while the latter is for the front-end. I understand your confusion because the front-end package/s are installable via NPM, although they are meant to be bundled with front-end code.

You can't do this:

import admin from 'firebase-admin' // back-end code
import { getAuth } from 'firebase/auth' // front-end code !!!

const adminApp = admin.initializeApp(...)
getAuth(adminApp) // TypeScript actually catches this error
/*
Argument of type 'App' is not assignable to parameter of type 'FirebaseApp'.
  Property 'automaticDataCollectionEnabled' is missing in type 'App' but required in type 'FirebaseApp'.ts(2345)
app-public.d.ts(92, 5): 'automaticDataCollectionEnabled' is declared here.
const adminApp: admin.app.App
*/

If you are on the back-end, just use adminApp.auth() to get the Auth instance. If on the front-end, you need to call getAuth with the front-end Firebase App instance:

import { initializeApp } from 'firebase/app'
import { getAuth } from 'firebase/auth'

const app = initializeApp(...)
const auth = getAuth(app)

The new modular apis have a slightly different syntax. The following should still work if you wrap it in a class, but as long as you only do this once at the top of your express? server you shouldn't need to use a class.

Also, I'm using the require syntax but imports should work too depending on your setup.

//Import each function from the correct module.
const { initializeApp, applicationDefault } = require("firebase-admin/app");
const { getAuth } = require("firebase-admin/auth");
const { getDatabase } = require("firebase-admin/database");

const app = initializeApp({
      credential: applicationDefault(), //Don't forget to export your configuration json https://firebase.google.com/docs/admin/setup
      databaseURL: "https://DATABASE_URL",
  });

const auth = getAuth(app)
const database = getDatabase(app)

It's not super well documented but you can find hints in the Admin SDK reference: https://firebase.google.com/docs/reference/admin/node/firebase-admin.auth

One tip: In VSCode you should see the a description of each function when you hover over them, if you have the import path formatted correctly.

Related