I am trying to import existing data from firestore to Algolia but can not make it work. I installed the *Firebase Algolia Extension` and tried to follow the documented steps:
running this:
npx firestore-algolia-search
Below are the questions that will be asked:
What is the Region? europe-west3
What is the Project Id? wishlist-88d58
What is the Algolia App Id? 15W2O5H8ZN
What is the Algolia Api Key? { unspecified parameter }
What is the Algolia Index Name? allUsers
What is the Collection Path? allUsers
What are the Fields to extract? { unspecified parameter }
What is the Transform Function? { unspecified parameter }
What is the path to the Google Application Credential File? wishlists_key.json
For the Algolia API Key I added a key:
I did not specify Fields to extracts and Transform Functions.
For path to the Google Application Credential File I created a private key in Firebase and located it on the my desktop as wishlists_key.json, which is where I ran the command above from.
I got a response which also contained the data but said at the beginning there was an error:
{"severity":"WARNING","message":"Warning, FIREBASE_CONFIG and GCLOUD_PROJECT environment variables are missing. Initializing firebase-admin will fail"}
{"location":"europa-west3","algoliaAppId":"15W205H8ZN","algoliaAPIKey":"********","algoliaIndexName":"allUsers","collectionPath":"allUsers","fields":"","transformFunction":"","projectId":"wishlist-88d58","severity":"INFO","message":"Initializing extension with configuration"}
{"severity":"INFO","message":"[ 'Sending rest of the Records to Algolia' ]"}
{"severity":"INFO","message":"[ 'Preparing to send 20 record(s) to Algolia.' ]"}
{"name":"RetryError","message":"Error when performing Algolia index","transporterStackTrace":[{"request":{"data":"{"requests":[{"action":"partialUpdateObject","body":{"signInMethod":"mail","username":"user662572"
...
The command does not finish running but get's stuck in this.
What am I doing wrong here? How do I correctly import data from FireStore to Algolia?
Also, later I will need to import a collection with about 24k documents. Is the documented way also capable of handling these amount of documents?
I was able to make it work through Google Cloud Shell. I had to import my Google Application Credential File to it, ran the command above again.
I still got the same Warning that it will fail, but it worked anyway and all data was correctly imported.
This question was previously closed, telling me to "update the question so it focuses on one problem only;" I don't know what the problem is, and if I did, I wouldn't be posting this question. Regardless, I'll make some clarifications here:
I was previously using just the normal Firebase module (the one imported using "npm i firebase"); everything worked perfectly before. The issue has to do with the authentication (as far as I am aware) with the Firebase Admin SDK. I don't understand how I'm supposed to send this to the Heroku build without revealing the service account key JSON file on my GitHub.
As for the GOOGLE_APPLICATION_CREDENTIALS path, is there a way where I don't have to set it every session? The Heroku app restarts once a day, and I would need to somehow automate this entry process (or skip it entirely). That's the way I currently understand it. Here's a quote from a previous answer:
When I set the GOOGLE_APPLICATION_CREDENTIALS path, doesn't this only set it on my local machine?
Environment variables only work on the individual machine and process where they have been set. If you want it set on another machine and process, you will have to arrange for that separately. According to the documentation:
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.
My main question here is as follows: "I implemented the Firebase Admin SDK incorrectly. How do I do it the right way?"
Even just posting a link to guides that would help would be appreciated (although I understand this is typically discouraged as links sometimes break).
Original:
Note: this is my first time using the Firebase Admin SDK, so I'm really not sure what I'm doing (although I have used Firebase quite a bit).
Recently, I decided I would go back to one of my older Discord bots and actually authenticate its requests to Firebase properly (I hadn't done this previously as I've never authenticated from a server before and didn't think it was possible). I discovered the Firebase Admin SDK, which sounded perfect for my needs (the bot is being hosted on Heroku, for the record).
I found this guide: https://firebase.google.com/docs/admin/setup, but there's a few things I can't wrap my head around (note that these are purely rhetorical, you don't need to answer them in your answer; I'm just providing them so you can understand my thought process):
When I set the GOOGLE_APPLICATION_CREDENTIALS path, doesn't this only set it on my local machine? I could also try running the export command on the server (using "heroku run" in the CLI), but then the path would be pointing to a file that doesn't exist on the server (since the service account key JSON file is on my local machine). Do I need to set an environment variable in Heroku or something?
How does "admin.credential.applicationDefault()" know how to get the credentials?
I can't find any other guides that make sense.
The way I currently have it setup must be wrong, since reads and writes fail silently.
Firebase setup code:
// Setup Firebase:
const admin = require('firebase-admin');
// Initialize Firebase:
admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: "https://<APP>.firebaseio.com" // I removed the actual <APP> name to ask this question
});
let database = admin.database();
Things like database.ref("test").set("Hello World!"); don't change the data in the database, and no errors are thrown (I've also tried attaching a .then and a .catch to the end of this; still nothing). This was working before I switched over to the Firebase Admin SDK (I was just using the "firebase" module previously, rather than the "firebase-admin" module that I'm now using). The same goes for reading data.
Any help would be appreciated.
Here was my problem:
I was sending res.status(200) outside of the async firebase call, killing the request before firebase had a chance to finish. Somehow localhost allows this to work properly but when its hosted things go sideways.
so I had this
fireabse.database().ref('parent/foo').set('bar');
res.status(200)
I needed this:
firebase.database().ref('parent/foo').set('bar').then(() => {
res.status(200);
});
I am attempting to write an onCall function for Firebase Cloud Functions that performs advanced querying tasks on a firestore database (i.e. checking a text query up against AutoML natural lang to get a category, etc) but I keep running into a problem trying to query the database from the function:
Error getting documents :: Error: Could not load the default credentials. Browse to https://cloud.google.com/docs/authentication/getting-started for more information.
at GoogleAuth.getApplicationDefaultAsync (/srv/node_modules/google-auth-library/build/src/auth/googleauth.js:161:19)
at <anonymous>
at process._tickDomainCallback (internal/process/next_tick.js:229:7)
Function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
exports.query = functions.https.onCall((data, context) => {
const text = data.text;
var results = [];
const promise = db.collection('providers').get()
promise.then((snapshot) => {
console.log('marker');
snapshot.forEach((doc) => {
results.push({id: doc.id, data: doc.data()});
});
console.log('yessir');
return {results: results};
}).catch((err) => {
console.log('Error getting documents :: ', err)
console.log('nosir');
return {results: "no results"};
});
});
Longer output:
Function execution started
Function execution took 8ms, finished with status code: 200
Error getting documents :: (etc, same error)
nosir
Example 2 (no change in running):
Function execution started
Function execution took 1200 ms, finished with status code: 200
marker
yessir
I can't figure out where this problem is coming from or how to resolve it.
Any help?
Regards.
What I first did to solve it was add my firebase admin sdk key to my project.
I downloaded it at
https://console.firebase.google.com/u/0/project/**YOUR_PROJECT_ID**/settings/serviceaccounts/adminsdk
then at admin.initializeApp(); I changed to:
admin.initializeApp({
credential: admin.credential.cert(require('../keys/admin.json'))
});
My folder structure is
├── key
│ ├── admin.json
├── src
│ ├── index.ts
HOWEVER, a better practice and safer approach, as some mentioned already:
You could use environment variables to store your credentials, this way you won't commit it to a repository such as Github, keep it safer from safety breaches and won´t make it hardcoded.
Depending on your project and where you'll deploy it there's a different way to do it.
There are many tutorials around on how to create and access env variables (like this one), but you could use a name it like the example below:
GOOGLE_APPLICATION_CREDENTIALS="/home/admin.json"
I had the same error "Could not load the default credentials".
The error occured after updating my project dependencies with npm update.
More precisely firebase-admin and firebase-functions.
Before update:
"dependencies": {
"#google-cloud/firestore": "^1.3.0",
"firebase-admin": "~7.0.0",
"firebase-functions": "^2.2.0"
}
After update:
"dependencies": {
"#google-cloud/firestore": "^1.3.0",
"firebase-admin": "^8.6.0",
"firebase-functions": "^3.3.0"
}
I added the serviceAccountKey.json to my project and changed the imports with the code provided at the service account setting of my firebase project.
From :
var admin = require('firebase-admin')
admin.initializeApp()
To:
var admin = require('firebase-admin');
var serviceAccount = require('path/to/serviceAccountKey.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: 'https://my-project.firebaseio.com'
});
See #Fernando Rocha's answer below to access the account setting of your firebase project.
#aldobaie's answer helped me figure out what was going on for my use case. For those who are not looking to add async/await to all their calls, remember that the firestore calls return promises, so prepending them with return has the same effect.
In my case:
function doSomething(...) {
return admin.firestore().collection(...).doc(...).get()
.then((doc) => {...})
.catch(err => {...})
}
module.exports = functions.firestore.document('collection/{docId}').onWrite((change, context) => {
return doSomething()
})
I think the accepted answer goes against Firebase's recommend configuration. The function environment has access to admin credentials already, and passing your key in the code is not recommended.
I do it like this:
const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase)
I ran into the same problem myself. Sometimes the function works and many times it would through the Error: Could not load the default credentials error.
The problem I believe have been solved by watching for the Callbacks. You have to keep the function running until the callbacks have been called using the await and async prefixes.
Firebase Cloud Functions don't allow the access to the processor through callbacks once it's been terminated! That's why we get the Error: Could not load the default credentials error.
So, whenever you have a .then() function prefix it with await and prefix the function it's inside it with async and prefix any call to the function with await.
async function registerUser(..) {
...
await admin.firestore().collection(..)...
...
}
I hope this helps you out!
Another option is to set the service account key in an environmental variable instead of setting it with a call to firebaseAdmin.initializeApp({ credential }).
Linux
export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/[FILE_NAME].json"
Windows PowerShell
$env:GOOGLE_APPLICATION_CREDENTIALS="[PATH]"
$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\[FILE_NAME].json"
Postscript: An even better option might be to use the local emulator suite.
Alright, so I had this error as well and spent a frustrated few days going over multiple sites, articles, videos, etc to try and figure out the cause of this problem so I could get an adequate answer for both myself and everyone else who is struggling.
There are answers to this question in this thread already. However, I tried following most of them to no avail. Some have security issues and others are just too vague to follow. I decided to post a thorough answer which also addresses the security issues you would have if you followed some of the other answers.
Alright now that I've gotten that out of the way lets get started!
First of all your going to need to go to this link - Getting started with authentication
You should see this in the center of your screen -
Next, click on the button I've marked in green. This will bring you to the create service account key page.
You should see a similar screen to the below image -
For the Service Account option, select new service account.
Create a name for your service account. This is not important, name it whatever you like.
For the role option select Project -> Owner
Finally, select JSON option for key type and then hit create.
This should create and download a .json file. Place this file somewhere smart and safe. I created a folder called 'credentials' in the root of my project and placed it in there.
Also I renamed the file to something more readable. While this isn't necessary, following good file/folder naming and structuring practices is important and I would advise you to rename it to something more readable.
(Its important to note that this file is personal and should not be included in any github repositories/firebase production/etc. This file is for you and you alone!)
Next open a command prompt window and type in the following command -
set GOOGLE_APPLICATION_CREDENTIALS=C:\Users\Username\Path\To\File\filename.json
This will create an environment variable that is linked securely to your credentials which firebase will recognize and use when you make calls to authenticate yourself.
(Note - This is the command for windows. If your using mac/linux go to the 'Getting started with Authentication' page mentioned earlier to get the appropriate command for your operating system)
There you go, the issue should now be fixed. If anyone has any further questions or problems feel free to comment below and i'll do my very best to help you. I know how frustrating it can be to be stuck with an error like this.
I hope this helps someone at the very least. Happy Programming.
C.Gadd
I do not want to use #Fernando solution even though there is nothing wrong.
I have prd and non-prd environment. I use firebase use command to push the changes to the correct environment. When I deploy, firebase uses the default service account. Also I do not want to have the keys in the project folder or in my git repo.
The way I solved might not work for others, but want to share here.
The issue came to me when I updated the permission of the firebase project to give a viewer with editor permission. I made that person the owner and rolled back to editor. It went away. It is not justifying as a fix, but worked for me and I do not have to download the key.
Instead of setting serviceAccountKey.json file, you can first set .env values from it and then use those:
import * as firebaseAdmin from "firebase-admin";
const adminCredentials = {
credential: firebaseAdmin.credential.cert({
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
privateKey: JSON.parse(process.env.FIREBASE_PRIVATE_KEY || ""),
}),
databaseURL: process.env.NEXT_PUBLIC_FIREBASE_DATABASE_URL,
};
if (!firebaseAdmin.apps.length) {
firebaseAdmin.initializeApp(adminCredentials);
}
const firestore = firebaseAdmin.firestore();
Old answer:
This is a known bug in Firebase. see the progress here: https://github.com/firebase/firebase-tools/issues/1940
However, meantime there are few options to resolve this:
1 Explicitly passed via code
var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your-app.firebaseio.com"
});
Not recommended this hard-coding. This json file will not be accessible on server.
2 Passed via GOOGLE_APPLICATION_CREDENTIALS
I'd recommend this way, set environmental variable:
GOOGLE_APPLICATION_CREDENTIALS=path/to/serviceAccountKey.json
For windows: (considering json is at your root path of project.
using powershell:
$env:GOOGLE_APPLICATION_CREDENTIALS='serviceAccountKey.json'
using NPM script: (notice no space before &&)
"serve": "set GOOGLE_APPLICATION_CREDENTIALS=serviceAccountKey.json&& npm run start",
(for some reason cross-env didn't work)
3 Available at a well-known filesystem path due to gcloud
by installing gcloud sdk and running gcloud auth application-default login
4 Available from the Compute Engine metadata API when running on GCP
I had same problem in firebase Error: "Could not get default credentials."
Then go to firebase console and go to project setting, where you can find Service Accounts option. Click there and you will see the Generate new private key under your project setting.
Copy code for your project language and add it to your project file.
var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://your-database-url-that-is-given-under-admin-sdk-snippets"
});
After Generating the key you will have option to download. and put it in the project folder. Also set path var serviceAccount = require("path/to/serviceAccountKey.json");
That's it your are ready.
None of above.
You may just:
firebase login - It will open browser login
As soon as you do login, returnto console and run:
firebase init - It will run as successfull.
I had the same issue.
Go on your settings page on Firebase => Service and Account.
Firebase Setting 1. Parameters 2. Account 3. Download the file and rename it [admin.json]
Copy the code and paste it
Requires 'admin.json' and paste, and run Firebase deploy.
admin.initializeApp(functions.config().firebase);
also works.
This error can also occur when the cloud function is not terminated properly.
Whenever you write a cloud function make sure you return promise after the cloud function processing is over, so that cloud function knows that your process is complete.
If you don't return promise then there might be chances where your cloud function might terminate before the processing is complete.
You can refer this to know how to terminate the cloud function.
Terminate cloud functions
Download your firebase service account into your project and reference it like this:
<code>
var admin = require("firebase-admin");
var serviceAccount = require("path/to/serviceAccountKey.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "<database-url>"
});
</code>
For those who come here from a serp trying to figure out why their google cloud function fails with:
Error: Could not load the default credentials. Browse to
https://cloud.google.com/docs/authentication/getting-started for more
information. at GoogleAuth.getApplicationDefaultAsync
but none of the above helped, you can try to update all(?) of your #google/whatever dependencies:
npm i -E #google/firestore#latest. Then rebuild, deploy, try again. It happened to me a few times recently and this worked.
I just had the same problem. To solve it, just update your node packages by npm update inside your project-dir/functions/ directory. Finally, deploy again.
On MacOS I had to do the following:
export GOOGLE_APPLICATION_CREDENTIALS=/Users/myname/serviceAccountKey.json
I was getting credential error because the locally running functions emulator could not securely talk to firebase auth running in production.
Google Cloud Reference
For those who still get the same problem event after downloading account key and using it inside your code, make sure it is inside your functions folder.
One thing it's a bit difficult to find in the docs is the firebase-admin SDK only uses the emulators when environment variables tell it to. If you use the service account JSON key as described in some answers here, firebase-admin will talk to prod (on Google Cloud) rather than the emulated version, even if everything else you're doing is on the emulators.
Since most likely you would rather use the emulators for local testing, here's how I set my environment variables in Mac ~/.zshrc:
export GCLOUD_PROJECT="your-project-id"
export FIRESTORE_EMULATOR_HOST=localhost:8080
export FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
export FIREBASE_DATABASE_EMULATOR_HOST=localhost:9000
The GCLOUD_PROJECT id could be your project id, but apparently any id will work as long as it is a well-formed Firebase project id, so these same environment variables can be used to test all your projects on the Firebase emulators. Try setting these environment variables first for emulator use before you try any of the other solutions.
Another oddity is firebase emulators:start needs these environment variables set, but firebase emulators:exec sets them automagically. When you are in a CI scenario :exec is the better choice, but when actively running tests as you write code having the emulators stay up and running with :start is a faster loop and you'll need the environment variables for it to work properly. By having these in environment variables, your code won't need to change at all when deployed to the Cloud.
I just had this issue and fixed it with
firebase login
I have been looking for a method in order to add the google-services.json at runtime as we use same base code to configure the application for the different client, hence we want to add google-services.json at runtime.
I have tried several links but am unable to find such a way to do it.
Any help will be very much appreciated.
The google-services.json is actually never read at runtime. During the build process of your Android app, the relevant information from google-services.json is translated into your App's XML resources, and that is where it's read when the app starts. Since the destination where the build plugin puts the values is hard-wired, you can't configure it to have multiple sets of configuration data.
Instead of trying to read google-services.json at runtime, I'd recommend configuring the FirebaseApp instance in your code explicitly, like this:
// Manually configure Firebase Options
FirebaseOptions options = new FirebaseOptions.Builder()
.setApplicationId("1:27992087142:android:ce3b6448250083d1") // Required for Analytics.
.setApiKey("AIzaSyADUe90ULnQDuGShD9W23RDP0xmeDc6Mvw") // Required for Auth.
.setDatabaseUrl("https://myproject.firebaseio.com") // Required for RTDB.
.build();
Now you can determine yourself where to keep the relevant information from the google-services.json and which ones to use when the app starts.
and then:
// Initialize with secondary app.
FirebaseApp.initializeApp(this /* Context */, options, "secondary");
// Retrieve secondary app.
FirebaseApp secondary = FirebaseApp.getInstance("secondary");
// Get the database for the other app.
FirebaseDatabase secondaryDatabase = FirebaseDatabase.getInstance(secondary);
Also see:
The documentation section on using multiple build flavors (where I now copied the code snippets from)
My previous answer on a related topic (where I think the code snippets in the docs originated 😀)
I'm using Firebase as a simple game-server and have some settings that are relevant for both client and backend and would like to keep them in RemoteConfig for consistency, but not sure if I can access it from my cloud functions in a simple way (I don't consider going through the REST interface a "simple" way)
As far as I can tell there is no mention of it in the docs, so I guess it's not possible, but does anyone know for sure?
firebaser here
There is a public REST API that allows you to read and set Firebase Remote Config conditions. This API requires that you have full administrative access to the Firebase project, so must only be used on a trusted environment (such as your development machine, a server you control or Cloud Functions).
There is no public API to get Firebase Remote Config settings from a client environment at the moment. Sorry I don't have better news.
This is probably only included in newer versions of firebase (8th or 9th and above if I'm not mistaken).
// We first need to import remoteConfig function.
import { remoteConfig } from firebase-admin
// Then in your cloud function we use it to fetch our remote config values.
const remoteConfigTemplate = await remoteConfig().getTemplate().catch(e => {
// Your error handling if fetching fails...
}
// Next it is just matter of extracting the values, which is kinda convoluted,
// let's say you want to extract `game_version` field from remote config:
const gameVersion = remoteConfigTemplate.parameters.game_version.defaultValue.value
So parameters are always followed by the name of the field that you defined in Firebase console's remote config, in this example game_version.
It's a mouthful (or typeful) but that's how you get it.
Also note that if value is stored as JSON string, you will need to parse it before usage, commonly: JSON.parse(gameVersion).
Similar process is outlined in Firebase docs.