Firebase Auth Admin SDK denied when using application default credentials
May 5, 2024
May 5, 2024
If youâre using the Firebase Admin SDK from your development machine e.g. to run ad hoc scripts, you may have tried to do something like this:
import admin from 'firebase-admin'
import { applicationDefault } from 'firebase-admin/app'
admin.initializeApp({
projectId: 'my-project',
credential: applicationDefault()
})
const auth = admin.auth()
const user = await auth.getUserByEmail('foo@bar.com')
console.log(user)
After all, it works just fine with other Firebase APIs like Firestore.
But in the above case, youâd be getting the following error (spread onto lines for readability):
FirebaseAuthError: //cloud.google.com/docs/authentication/.
If you are getting this error with curl or similar tools, you may need
to specify 'X-Goog-User-Project' HTTP header for quota and billing
purposes.
For more information regarding 'X-Goog-User-Project' header, please
check https://cloud.google.com/apis/docs/system-parameters.
Raw server response:
{
"error": {
"code": 403,
"message": "Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the identitytoolkit.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters.",
"errors": [
{
"message": "Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the identitytoolkit.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/. If you are getting this error with curl or similar tools, you may need to specify 'X-Goog-User-Project' HTTP header for quota and billing purposes. For more information regarding 'X-Goog-User-Project' header, please check https://cloud.google.com/apis/docs/system-parameters.",
"domain": "usageLimits",
"reason": "accessNotConfigured",
"extendedHelp": "https://console.developers.google.com"
}
],
"status": "PERMISSION_DENIED",
"details": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "SERVICE_DISABLED",
"domain": "googleapis.com",
"metadata": {
"service": "identitytoolkit.googleapis.com",
"consumer": "projects/123456"
}
}
]
}
}
}
So whatâs going on? Well applicationDefault()
works with the
application default credentials as created by
gcloud auth application-default login
,
which live in ~/.config/gcloud/application_default_credentials.json
.
In my case, those credentials didnât have access to Firebase Auth for a reason I did not try to understand.
However, what did have access to Firebase Auth is the application
default credentials as created by firebase login
,
which live in ~/.config/firebase/*_application_default_credentials.json
.
Firebaseâs applicationDefault()
, despite being a method of the
Firebase SDK, does not know
about the Firebase application default credentials, and instead only
uses the Google Cloud credentials. đ
However it supports reading the credentials file from the
GOOGLE_APPLICATION_CREDENTIALS
environment variable, so we can run the
script like this:
GOOGLE_APPLICATION_CREDENTIALS=~/.config/firebase/*_application_default_credentials.json node script.js
Note: I left a wildcard *
in the path above because Firebase
application default credentials contain your user and organization name.
Itâll work out of the box if you are only connected to a single Firebase
identity, but youâll have to be more specific otherwise.