firebase-tools: Firestore emulator: PERMISSION_DENIED
[REQUIRED] Environment info
firebase-tools: 6.10.0
Platform: macOS
[REQUIRED] Test case
This will take a moment, brb
[REQUIRED] Steps to reproduce
- Setup a Java project with the Firestore gcloud SDK, or the Firebase Admin SDK. Either way, make sure you’re on the newest Firestore release. In Gradle, for us, that’s:
compile group: 'com.google.cloud', name: 'google-cloud-firestore', version: '1.6.0'
- Install the latest gcloud SDK locally. Gcloud reports the following for
gcloud --version
:
Google Cloud SDK 248.0.0
alpha 2019.05.17
app-engine-go
app-engine-java 1.9.74
app-engine-python 1.9.85
beta 2019.05.17
bq 2.0.43
cloud-build-local
cloud-datastore-emulator 2.1.0
cloud-firestore-emulator 1.4.6
cloud_sql_proxy
core 2019.05.24
docker-credential-gcr
emulator-reverse-proxy
gsutil 4.38
pubsub-emulator 2019.04.26
- Write up a rules file for local emulator access to Firestore. Try your hardest to make it fully open - i.e. allow all traffic for basic testing.
rules_version = '2';
service cloud.firestore {
match /databases/{database} {
allow read, write: if true;
match /{document=**} {
allow read, write: if true;
}
}
}
- Try to run
listDocuments()
on a query, receive the following exception:
com.google.cloud.firestore.FirestoreException: io.grpc.StatusRuntimeException: PERMISSION_DENIED: Metadata operations require admin authentication.
at com.google.cloud.firestore.FirestoreException.apiException(FirestoreException.java:79)
at com.google.cloud.firestore.CollectionReference.listDocuments(CollectionReference.java:140)
[... lots of user code...]
- Think to yourself, okay, I’ll play this dumb credentials game. So you load up your JSON service account key file, and inject the credentials into the Firestore adapter, like you do for production access to Firestore:
public static @Provides FirestoreOptions getFirestoreOptions() {
// [... lots of prep ...]
if (emulator) {
final CredentialsProvider adminCreds = FixedCredentialsProvider.create(googleCreds);
opts.setCredentials(googleCreds);
opts.setCredentialsProvider(credentialsProvider);
return opts.build();
}
return opts.build();
}
- Run it again. Observe the following exception, because the emulator isn’t running via TLS, we see that the request is rejected again, this time because you cannot use credentials over a plaintext connection:
Caused by: com.google.api.gax.rpc.UnauthenticatedException: io.grpc.StatusRuntimeException: UNAUTHENTICATED: Credentials require channel with PRIVACY_AND_INTEGRITY security level. Observed security level: NONE
at com.google.api.gax.rpc.ApiExceptionFactory.createException(ApiExceptionFactory.java:73)
[REQUIRED] Expected behavior
It should be possible to run queries on the local emulator for Firestore.
[REQUIRED] Actual behavior
Because of this catch-22 error setup, I don’t believe there is a way to run queries on the local emulator for Firestore, at least not queries that involve “metadata.”
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Comments: 35 (13 by maintainers)
It is indeed expected behavior. You will need to be authenticated as an admin. The upside is that it’s actually much simpler than authenticating against prod firestore: all you need to do is pass in an
"Authorization: Bearer owner"
header. The bearer"owner"
is accepted by the emulator for all projects.If you’re familiar with @google-cloud/firestore you should be able to use the Admin SDK like so:
@antoniooi there have been a few bugs in the Admin SDK which are now all fixed (remove your node_modules and package-lock.json and run npm install again).
If you still have this error, please file a new issue with the simplest possible steps to reproduce and I’ll dig into it.
@antoniooi looks like there are a few things that may be going wrong:
databaseURL
is a setting for Realtime Database, not Cloud Firestore. Pointing that at your Firestore emulator could cause unknown issues.You are using this method to connect to the emulator:
That’s actually how you connect the web JavaScript SDK to the emulator. The best way to connect the Admin SDK to the emulator is by using an environment variable:
If that is set in your environment, when you do
admin.initializeApp()
we will automatically pick it up and connect to the emulator.If you’re still having issues after trying these fixes, please open a new issue.
For anyone using ruby and arriving here via google, here’s a workaround for the
google-cloud-firestore
gem:@samtstern : Work like a charm with the following steps:
functions/node_modules
andfunctions/package-lock.json
.npm install
at thefunctions
directory.firebase emulators:start
.set FIRESTORE_EMULATOR_HOST=localhost:8080
.node import-test-data.js
--> Test data go into the Firestore Emulator! 👍firestore.rules
toallow read, write: if false;
.node import-test-data.js
again --> No more PERMISSION_DENIED error. Test data updated at the Firestore Emulator accordingly! 👍Everything works perfectly! All problems solved! Well done! 👍
I’ve probably faced the same problem, as the Admin SDK seems to be affected by the rules.
I tried emulators-codelab (https://github.com/firebase/emulators-codelab/tree/master/codelab-final-state) but functions emulator could not work properly.
Cart could not be recalculated. Error: 7 PERMISSION_DENIED:
error log appeared from this code.https://github.com/firebase/emulators-codelab/blob/b6c759ab8c6ba3f9f955cb248ee906021e09cf5f/codelab-final-state/functions/index.js#L28
Then I commented out all existing rules in
firestore.rules
and rewrote them toallow read, write;
, emulator worked correctly.Using firebase-tools version is here.
@samtstern : I think it is not the Admin SDK problem. It could be the Firestore emulator that is still bothering too much about the security rules and forgotten about Admin SDK privilege. If I go directly to the production server without running the emulators, the Admin SDK works as it should be – even with the rule
allow read, write: if false;
. I believe it is the emulator that is blocking it based on the rules.@samtstern : Thanks for enlightening me. I didn’t know that
databaseURL
is only meant for Real-time Database. No wonder no matter what URL I put in, it still works, LOL. As for thedb.settings
, I tried before, without it, I can’t insert test data in my Firestore Emulator and make it appears in emulator UI – it will go straight to the Firestore production server despite Firestore emulator is properly running.Honestly speaking, I’m just a beginner. Hope you don’t mind if I seek help from you further, where should I put this line of code:
export FIRESTORE_EMULATOR_HOST=localhost:8080
Is the above code just a pseudo or a fully functional code? Sorry for asking this because many experts here like to give only a “concept”, and made me foolishly hit the wall all the time. @_@
As what I know, when I start the emulator, the
process.env
shows that this has already been set for me, why should I set it again in my code? Thanks in advance!Got it working, a bit hackily: https://gist.github.com/ryanpbrewster/aef2a5c411a074819c8d7b67be80621c
LMK if that’s enough to get you going
It also wouldn’t be too hard to implement this as a
CredentialProvider
ingax
or what not. That would be super helpful, if you could point me in the right direction I’d be happy to file a PR or an issue in the right repo (because that’s way closer to general Google APIs Java than it is Firebase, if I’m not mistaken).Thank you btw for the quick reply Firebase team 😃
edit: @ryanpbrewster feel free to close as
wontfix
once you reply.The REST API looks like
Out of curiosity, which SDK are you using here? Based on the stack trace it looks like Java?