I am struggling to connect to the emulated Firebase Auth service via the Firebase Admin SDK. I cut down the code to really make the problem stand out, and hope someone can help.
This is the code of the test.js I run (in NodeJS):
// Someone said these two lines should allow the firebase-admin
// SDK to connect to the emulators, but... no.
process.env['GCLOUD_PROJECT'] = 'my-firebase-project-id'
process.env['FIRESTORE_EMULATOR_HOST'] = 'localhost:8080'
const admin = require('firebase-admin')
const app = admin.initializeApp()
const auth = app.auth()
console.log('I have an auth service object')
auth.listUsers().then(users => console.log(users))
I run the emulators like this:
firebase emulators:start --only auth
When I run the test.js file, I get this:
PS C:\...\functions> node .\test.js
I have an auth service object
(node:18232) UnhandledPromiseRejectionWarning: Error: Credential implementation provided to initializeApp() via the "credential" property failed to fetch a valid Google OAuth2 access token with the following error: "Error fetching access token: Error while making request: getaddrinfo EAI_AGAIN metadata.google.internal. Error code: EAI_AGAIN".
at FirebaseAppError.FirebaseError [as constructor] (C:\...\functions\node_modules\firebase-admin\lib\utils\error.js:44:28)
at FirebaseAppError.PrefixedFirebaseError [as constructor] (C:\...\functions\node_modules\firebase-admin\lib\utils\error.js:90:28)
at new FirebaseAppError (C:\...\functions\node_modules\firebase-admin\lib\utils\error.js:125:28)
at C:\...\functions\node_modules\firebase-admin\lib\app\firebase-app.js:87:19
at processTicksAndRejections (internal/process/task_queues.js:97:5)
I run this on Windows with the following versions of firebase:
"firebase-admin": "^10.0.2",
"firebase-functions": "^3.18.1",
I read about getting a secret credentials key and adding its path like this:
process.env['GOOGLE_APPLICATION_CREDENTIALS'] = 'C:\\...\\functions\\.runtimekey.json'
And that 'works' in as much as I then can access the real cloud auth instance (as long as the emulators is off) but that isn't what I want. I want to connect firebase-admin and get a list of users in the emulated Auth instance.
Many thanks for any help you can offer!
Set the environment variable FIREBASE_AUTH_EMULATOR_HOST
export FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
Do not include the protocol scheme (i.e http/https)
Or in your case:
process.env['FIREBASE_AUTH_EMULATOR_HOST'] = 'localhost:9099'
Then you can initialise the app as per normal
admin.initializeApp()
Worked for me (after I finally figured out not to include the protocol scheme)
source: https://firebase.google.com/docs/emulator-suite/connect_auth#admin_sdks
Related
Without having changed anything in my Firebase callable functions code, but having re-deployed them, now they suddenly start rejecting all function invocations from my app with the error shown below. I would like NOT to use App Check until I am ready to make the changes needed. How do I stop my callable (https.onCall) Firebase functions from rejecting invalid App Checks, and instead only reject invalid Authentication?
Failed to validate AppCheck token. FirebaseAppCheckError: Decoding App Check token failed. Make sure you passed the entire string JWT which represents the Firebase App Check token.
at FirebaseAppCheckError.FirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:44:28)
at FirebaseAppCheckError.PrefixedFirebaseError [as constructor] (/workspace/node_modules/firebase-admin/lib/utils/error.js:90:28)
at new FirebaseAppCheckError (/workspace/node_modules/firebase-admin/lib/app-check/app-check-api-client-internal.js:187:28)
at /workspace/node_modules/firebase-admin/lib/app-check/token-verifier.js:82:19
at processTicksAndRejections (internal/process/task_queues.js:97:5) {
errorInfo: {
code: 'app-check/invalid-argument',
message: 'Decoding App Check token failed. Make sure you passed the entire string JWT which represents the Firebase App Check token.'
},
codePrefix: 'app-check'
}
Callable request verification failed: AppCheck token was rejected. {"verifications":{"app":"INVALID","auth":"VALID"}}
The code rejecting all requests due to invalid App Check is super simple:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
exports.example = functions.https.onCall((data, context) => {
return "test";
}
Package.json:
"engines": {
"node": "12"
},
"main": "index.js",
"dependencies": {
"firebase-admin": "^9.10.0",
"firebase-functions": "^3.14.1"
},
I had the same experience. The docs say that you are supposed to check like this[1]:
if (context.app == undefined) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called from an App Check verified app.')
}
But, this is not the case in my experience, the App Check starts to be enforced immediately the moment you add App Check to your app.
EDIT:
moreover, even without doing any check in my code, I can see this in the logs whenever I call one of my functions:
Callable request verification passed {"verifications":{"auth":"VALID","app":"VALID"}}
So it seems App Check happens automatically, at least in Callable Functions. If you want to bypass AppCheck in one of your functions, you might want to try an HTTP function instead (not Callable).
[1] Source https://firebase.google.com/docs/app-check/cloud-functions
From protocol specification for https.onCall:
Optional [Header]: X-Firebase-AppCheck: The Firebase App Check token provided by the client app making the request. The backend automatically verifies this token and decodes it, injecting the appId in the handler's context. If the token cannot be verified, the request is rejected. (Available for SDK >=3.14.0)
My guess is that calls to your callable function contains an invalid App Check token.
If you haven't configured DeviceCheck or/and App Attest attestation providers on your project but have included the App Check library on your client, your client code may be including a dummy App Check token when calling your function (full details on this github issue).
Firebase team is working through changes to make the experience less confusing. Please follow along in http://github.com/firebase/firebase-functions/issues/967 and https://github.com/FirebaseExtended/flutterfire/issues/6794 for status.
My problem is the same when I run the app on an emulator, after running on a real device is running without any problems. That's what happens to me.
I have recently added Firebase App Check in my Flutter app.
I am calling Cloud functions with the https.onCall() method. However i am receiving this error :
> {"severity":"WARNING","message":"Failed to validate AppCheck token. FirebaseAppCheckError: Decoding App Check token failed. Make sure you passed the entire string JWT which represents the Firebase App Check token.
at FirebaseAppCheckError.FirebaseError [as constructor] (/Users/foxtom/Desktop/Cloud Functions/functions/node_modules/firebase-admin/lib/utils/error.js:44:28)
at FirebaseAppCheckError.PrefixedFirebaseError [as constructor] (/Users/foxtom/Desktop/Cloud Functions/functions/node_modules/firebase-admin/lib/utils/error.js:90:28)
at new FirebaseAppCheckError (/Users/foxtom/Desktop/Cloud Functions/functions/node_modules/firebase-admin/lib/app-check/app-check-api-client-internal.js:187:28)
at /Users/foxtom/Desktop/Cloud Functions/functions/node_modules/firebase-admin/lib/app-check/token-verifier.js:82:19
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
errorInfo: {
code: 'app-check/invalid-argument',
message: 'Decoding App Check token failed. Make sure you passed the entire string JWT which represents the Firebase App Check token.'
},
codePrefix: 'app-check'
}"}
> {"verifications":{"app":"INVALID","auth":"MISSING"},"logging.googleapis.com/labels":{"firebase-log-type":"callable-request-verification"},"severity":"WARNING","message":"Callable request verification failed: AppCheck token was rejected."}
The severity seems to be WARNING only but it doesn't execute the function. My function only contains a console.log()
In my app i have this error :
W/FirebaseContextProvider( 6788): Error getting App Check token; using placeholder token instead. Error: com.google.firebase.FirebaseException: Error returned from API. code: 403 body: App attestation failed.
I/flutter ( 6788): Error is : [firebase_functions/unauthenticated] Unauthenticated
I have not enforced anything like suggested in the documentation
This is preventing me from using Cloud Functions and i can disable App Check for my app anymore...
EDIT :
I add that Firebase Storage and RealTime Database are working fine without any debug AppCheck token when it's not enforced.
What can I do ?
I created a reproducible code sample, which you see here: https://github.com/nilsreichardt/playground/tree/firebase-app-check-cloud-function-unauthenticated-issue/firebase-app-check-cloud-functions-unauthentificated
Therefore, I created a detailed issue in the FlutterFire repository: https://github.com/FirebaseExtended/flutterfire/issues/6794
A first workaround already posted as a comment and I'm sure that more workarounds or solutions will follow.
Firebaser here.
Thank you for reporting this issue -- we have now released a fix to all platforms that should resolve this issue. Please refer to the Github issue for full details.
Does anyone know why Firebase admin auth in node.js doesn't use ADC (Application Default Credentials)? I always have to set GOOGLE_APPLICATION_CREDENTIALS to a credentials file to get auth to work. Everything else (firestore, compute, storage etc.) works fine with ADC.
For instance, this code works only when GOOGLE_APPLICATION_CREDENTIALS is set to a valid credentials file, even though I'm logged into my Firebase project and my gcloud project:
import * as admin from 'firebase-admin'
admin.initializeApp()
async function listAllUsers(users: any[], matchRegex: RegExp, nextPageToken?: string) {
// List batch of users, 1000 at a time.
const listUsersResult = await admin.auth().listUsers(1000, nextPageToken)
.catch(function (error) {
console.log('Error listing users:', error);
});
if (listUsersResult) {
listUsersResult.users.forEach(function (userRecord) {
if (matchRegex.test(userRecord.email || '<none>') ||
matchRegex.test(userRecord.displayName || '<none>') ||
matchRegex.test(userRecord.uid))
users.push(userRecord.toJSON())
});
if (listUsersResult.pageToken) {
// List next batch of users.
console.log(`next batch...`)
listAllUsers(users, matchRegex, listUsersResult.pageToken);
}
}
}
If that env var is not set, I get this error:
Error listing users: FirebaseAuthError: Failed to determine project ID for Auth.
Initialize the SDK with service account credentials or set project ID as an app option.
Alternatively set the GOOGLE_CLOUD_PROJECT environment variable.
But setting GOOGLE_CLOUD_PROJECT is not enough either. When I do that, I get:
Error listing users: FirebaseAuthError: //cloud.google.com/docs/authentication/. 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/.","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/.","domain":"usageLimits","reason":"accessNotConfigured","extendedHelp":"https://console.developers.google.com"}],"status":"PERMISSION_DENIED"}}"
at FirebaseAuthError.FirebaseError [as constructor] (/c/dss/Product/Horizon/horizon/packages/renderer/node_modules/firebase-admin/lib/utils/error.js:43:28)
at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/c/dss/Product/Horizon/horizon/packages/renderer/node_modules/firebase-admin/lib/utils/error.js:89:28)
at new FirebaseAuthError (/c/dss/Product/Horizon/horizon/packages/renderer/node_modules/firebase-admin/lib/utils/error.js:148:16)
at Function.FirebaseAuthError.fromServerError (/c/dss/Product/Horizon/horizon/packages/renderer/node_modules/firebase-admin/lib/utils/error.js:187:16)
at /c/dss/Product/Horizon/horizon/packages/renderer/node_modules/firebase-admin/lib/auth/auth-api-request.js:1490:49
As I said though, all other Firebase admin features seem to work fine with ADC; they automatically pick up the current project and my logged in account.
I am currently trying to deploy my Cloud Functions to Firebase with firebase deploy --only functions but this does not seem to work, it never finishes the deploy. I tried debugging the deploy with the command firebase deploy --only functions --debug, this prints out all the requests with the url's that lead to the error messages. Whenever i click one of the url's of the requests it gives me this error:
{
"error": {
"code": 403,
"message": "The request is missing a valid API key.",
"status": "PERMISSION_DENIED"
}
}
Some of the other url's give me this error:
{
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED"
}
}
I can't really find anything useful online on how to fix this either. The articles that i did find did not help me though.
This is my index.js file where my Cloud Functions are:
const functions = require('firebase-functions');
const {firestore, auth} = require('./src/admin');
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
exports.helloWorld = functions.https.onRequest((request, response) => {
response.send("Hello from Firebase!");
});
This is my admin.js file where i define the serviceAccountKey and such:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const serviceAccount = require('../serviceAccountKey.json');
const app = admin.apps.length
? admin.app()
: admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: functions.config().database.url || process.env.FIREBASE_CONFIG.databaseURL, // default firebase var
storageBucket: functions.config().storage.bucket || process.env.FIREBASE_CONFIG.storageBucket // default firebase var
});
module.exports = {
app,
firestore: app.firestore(),
db: app.database(),
storage: app.storage(),
auth: app.auth()
};
I have used this exact code before on another project so i assume its a Firebase problem and not my code. In the end i expect my Cloud Functions to be deployed by calling the firebase deploy --only functions command without any authentication errors.
Can someone please tell me what i am doing wrong here?
UPDATE 22-2-2020 12:44 PM: I tried reinstalling and reconfiguring the firebase-tools. After doing that and running the command again it gave me this error:
There was an issue deploying your functions. Verify that your project has a Google App Engine instance setup at https://console.cloud.google.com/appengine and try again. If this
issue persists, please contact support.
! functions: Upload Error: HTTP Error: 503, The service is currently unavailable.
Error: HTTP Error: 503, The service is currently unavailable.
The URL leads me to the page where you can setup your App Engine. Because i already set that up it says 'Your App Engine application has been created'. However whenever i click Get Started button again, i have to create a billing account to proceed. This is keeping me from deploying my Cloud Functions. Is there a way to use Cloud Functions with a billing account?
I'm trying to use OpenWeatherAPI for my Actions on Google project. I'm using Firebase Cloud Functions through Dialogflow. How can I make an API request to get data from OpenWeatherAPI?
request.get('http://api.openweathermap.org/data/2.5/uvi?appid=XXX&lat=37.75&lon=-122.37', function (error, response, body) {
console.log('error:', error);
console.log('statusCode:', response && response.statusCode);
console.log('body:', body);
});
Here are Firebase logs:
statusCode: undefined
body: undefined
error: { Error: getaddrinfo ENOTFOUND api.openweathermap.org api.openweathermap.org:80
at errnoException (dns.js:28:10)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:76:26)
code: 'ENOTFOUND',
errno: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'api.openweathermap.org',
host: 'api.openweathermap.org',
port: 80 }
By default, Firebase Cloud Functions and the Dialogflow editor use a project that is on Firebase's Spark plan. This is completely free, but does have some restrictions, including no network access outside of Google's services.
In order to access openweathermap.org, you will likely need to upgrade to a paid plan. I suggest the Blaze plan, which is pay as you go over a certain level of usage each month. You will need to register with a credit card, but the usage level for development (and even for a modest level of production usage) should be enough to keep you in the free tier.