Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid-credential error for admin.auth calls #1371

Open
jaschaio opened this issue Jun 5, 2019 · 19 comments
Open

Invalid-credential error for admin.auth calls #1371

jaschaio opened this issue Jun 5, 2019 · 19 comments

Comments

@jaschaio
Copy link

jaschaio commented Jun 5, 2019

Getting the Following Error when using initializeApp() within the functions emulator without a credentials file. This worked before on firebase-tools@6.8.0. Has this behaviour changed between 6.8.0 and 6.11.0? If yes, why isn't it within the changelogs? The docs actually say now that

All other APIs, including Firebase APIs such as Authentication and FCM or Google APIs such as Cloud Translation or Cloud Speech, require the setup steps described in this section. This applies whether you're using the functions shell or firebase serve.

Still wondering why it wasn't necessary in firebase-tools@6.8.0

Related issues

#1299 seems related, but I am using firebase serve instead of firebase emulators:start

Environment info

firebase-tools: 6.11.0
Platform: macOSX 10.14.5
Node: 10.15.3 (but ocurring with 8.14.0 as well)
firebase-functions: 2.3.1
firebase-admin: 8.0.0

Test case

A freshly generated firebase project using firebase init with functions. Install firebase-admin@8.0.0 and firebase-functions@2.3.1. Make sure you are running the latest firebase-tools@6.11.0. Run npm install --save grpc to prevent #1341.

Use Node 10.15.3 or 8.14.0 and change the package.json engines node to 10 or 8 respectively.

Than edit the functions/index.js file copying and pasting the below:

const functions = require( 'firebase-functions' );
const admin     = require( 'firebase-admin' );

admin.initializeApp();

exports.login = functions.https.onRequest( async ( req, res ) => {

    var users = await admin.auth().listUsers();

    res.json( users );

} );

Steps to reproduce

Run firebase serve within the newly created project as described above. Than make a request to the exported /login endpoint. The error will be thrown in the terminal console.

Expected behavior

No error should be thrown. The emulator should automatically have sufficient credentials to use firebaseAdmin.auth() methods.

Actual behavior

Your code has been provided a "firebase-admin" instance.
⚠  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: invalid_grant (Token has been expired or revoked.)". There are two likely causes: (1) your server time is not properly synced or (2) your certificate key file has been revoked. To solve (1), re-sync the time on your server. To solve (2), make sure the key ID for your key file is still present at https://console.firebase.google.com/iam-admin/serviceaccounts/project. If not, generate a new key file at https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk.
    at FirebaseAppError.FirebaseError [as constructor] (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:42:28)
    at FirebaseAppError.PrefixedFirebaseError [as constructor] (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:88:28)
    at new FirebaseAppError (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:122:28)
    at /Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/firebase-app.js:121:23
    at process._tickCallback (internal/process/next_tick.js:68:7)

If I downgrade back to firebase-tools@6.8.0 it works.

@samtstern
Copy link
Contributor

@jaschaio that's actually the new intended behavior although clearly it should be explained better. @abeisgoat can comment.

If you want to get the old behavior, try using firebase serve --only functions instead of firebase emulators:start --only functions. We have flagged off most of the new behavior in the serve version.

@abeisgoat
Copy link
Contributor

@samtstern looks like this isn't that issue because he's already using serve.

@jaschaio thanks for the helpful bug report. I was able to reproduce this behavior, although strangely, I only got it to work once. After downgrading to firebase-tools@6.8.0 and then upgrading back to 6.11.0, the issue no longer existed.

I suspect this is because when calling admin.initializeApp() without any arguments, it looks for the application default credential which was (perhaps on both our machines) out of date. When I went back and used the old emulator it shelled out to gcloud under the hood which updated my old access token.

One easy work around is to just create a dedicated service account in the Firebase console and provide the credential to initializeApp(), that'll totally work. However, I'd love if you could run gcloud auth application-default print-access-token which should refresh it and then see if that fixes the emulator. If it does, we may just need to do a shell out to gcloud to make sure application default creds are up to date.

@abeisgoat abeisgoat added the Needs: Author Feedback Issues awaiting author feedback label Jun 6, 2019
@samtstern
Copy link
Contributor

@jaschaio while the error you got is not related to what I am about to say, it was actually protecting you from another more serious error. And fixing one will fix both, so let's just jump to that.

Ok so when you run admin.initializeApp() it does this process to search for credentials:
https://cloud.google.com/docs/authentication/production#finding_credentials_automatically

When you're running in Cloud Functions it finds a service account and everything is great. When you're running locally it finds the credential you probably set up with gcloud auth application-default login which is a user credential that has a Client ID that points to the shared gcloud project. You don't have to care about that detail at all. However if you do try and use that credential to run admin.auth().listUsers() you will get an error like this one:

Error: //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 that most server applications use service accounts instead. 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 that most server applications use service accounts instead. 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"}}"

So the way to solve this is to make sure you set GOOGLE_APPLICATION_CREDENTIALS and point it to a service account JSON file for your project.

So you'd do:

GOOGLE_APPLICATION_CREDENTIALS=your_service_account.json firebase serve

Note that this is specific to the Auth API. You'll notice that the Firestore API accepts these "user credentials" without any complains. Both APIs consider this situation "working as intended" and for now there is nothing we can do to work around it in the emulator.

I hope that makes sense!

@JFGHT
Copy link

JFGHT commented Jun 10, 2019

I just came into this very same problem.

So does this mean that, if you did firebase login, then firebase use X and you're running functions with serve and NOT emulators:start, it will still not work just like in previous versions?

Edit:

For testing purposes, I installed gcloud and did gcloud auth application-default login resulting in success. Then, when running my function, the error @samtstern quotes appears.

Is there no other way to auth than to create this file?

I fully understand your goal of isolating us from production, but in some situations we really want to test with live database... and dumping the service account credentials into a file is not always the best and safest approach.

Kind of happens a similar thing with the config variables, that you have to hit firebase functions:config:get > .runtimeconfig.json so you can get them work. I don't think this should be the case if you're using the serve command.

@abeisgoat
Copy link
Contributor

@JFGHT Thanks for the thoughts - there's definitely some unintended behavior going on here, we want isolation by default but with the option to access production if you like. The authentication aspect of this is a hard problem worked on by many teams so it's made tougher because everyone needs to stay on the same page, but we're working on it :)

In regards to creating and setting the default credential, there are other options (like supplying an environmental variable), but we're still in the process of communicating with folks to figure out what they recommend people to use so we know what to recommend you to use.

We'll definitely smooth this out so we'll keep updating here as we figure out what we're doing.

@samtstern samtstern removed the Needs: Author Feedback Issues awaiting author feedback label Jun 14, 2019
@jaschaio
Copy link
Author

jaschaio commented Jul 3, 2019

Hey @abeisgoat & @samtstern, thanks for your input.

Exporting GOOGLE_APPLICATION_CREDENTIALS worked for a while but now after updating to firebase-tools@7.0.2 I am getting a different error:

Error: //developers.google.com/identity/sign-in/web/devconsole-project. Raw server response: "{"error":{"code":401,"message":"Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.","errors":[{"message":"Invalid Credentials","domain":"global","reason":"authError","location":"Authorization","locationType":"header"}],"status":"UNAUTHENTICATED"}}"
    at FirebaseAuthError.FirebaseError [as constructor] (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:42:28)
    at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:88:28)
    at new FirebaseAuthError (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:146:16)
    at Function.FirebaseAuthError.fromServerError (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:185:16)
    at /Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/auth/auth-api-request.js:1139:49
    at process._tickCallback (internal/process/next_tick.js:68:7)

Test Case is the same as above, but using firebase-tools@7.0.2 instead of 7.0.0. If I downgrade to 7.0.0 it works. It works as well using the latest versions of firebase-admin and firebase-functions but stops working as soon as I update firebase-tools to 7.0.2.

It happens when using any firebase.admin.auth method that requires credentials. I can confirm that the service account works and the environment variable GOOGLE_APPLICATION_CREDENTIALS is properly set (if not it would fail using 7.0.0)

Should I open a new issue or keep this one?

@samtstern samtstern changed the title 6.11.0 app/invalid-credential error Invalid-credential error for admin.auth calls Jul 3, 2019
@samtstern
Copy link
Contributor

@jaschaio so to be clear you're getting issues with admin.auth calls when running GOOGLE_APPLICATION_CREDENTIALS=... firebase serve? And these issues only happen on 7.0.2 and above? If that's the case let's keep it in this issue.

@jaschaio
Copy link
Author

jaschaio commented Jul 3, 2019

Yes. Try the test case above. It works with 7.0.0 and fails with this error on 7.0.2

Error: //developers.google.com/identity/sign-in/web/devconsole-project. Raw server response: "{"error":{"code":401,"message":"Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.","errors":[{"message":"Invalid Credentials","domain":"global","reason":"authError","location":"Authorization","locationType":"header"}],"status":"UNAUTHENTICATED"}}"
    at FirebaseAuthError.FirebaseError [as constructor] (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:42:28)
    at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:88:28)
    at new FirebaseAuthError (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:146:16)
    at Function.FirebaseAuthError.fromServerError (/Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/utils/error.js:185:16)
    at /Applications/MAMP/htdocs/debug/functions/node_modules/firebase-admin/lib/auth/auth-api-request.js:1139:49
    at process._tickCallback (internal/process/next_tick.js:68:7)

@kevlened
Copy link

kevlened commented Jul 8, 2019

To help narrow the search, 7.0.1 doesn't throw this error for me.

@ZaneH
Copy link

ZaneH commented Jul 17, 2019

I don't know if anyone else is dumb enough to try what I did,

But I fixed this issue by going to the Firebase console and creating a Service account from there instead of creating a Service account from the GCP IAM & Admin area. Then I initialized the project with:

var serviceAccount = require('./myproject-1234.json');

admin.initializeApp({
    projectId: 'myproject',
    credential: admin.credential.cert(serviceAccount),
});

@pgardner-squadpod
Copy link

pgardner-squadpod commented Jul 19, 2019

Downgrading my firebase-tools package to 7.0.0 fixes the problem for me.

npm i -g firebase-tools@7.0.0

Be sure you check you're on the right version. I had a funky setup not too long ago where 6.x was still creeping up after an update:

firebase --version

@jaschaio
Copy link
Author

jaschaio commented Aug 10, 2019

This seems fixed for me within firebase-tools@7.2.2 and making sure the environment variable GOOGLE_APPLICATION_CREDENTIALS is set to a service account .json file (Using the one from the Firebase Console)

@samtstern
Copy link
Contributor

@jaschaio yes that will work, however we want this to work with "application default" credentials so users don't have to think about service accounts in testing (just like you don't have to in production).

@astyltsvig
Copy link

astyltsvig commented Sep 18, 2019

@samtstern Any update on that issue?

@f-gueguen
Copy link

f-gueguen commented Sep 26, 2019

Using the following dependencies fixed it for me (with node 10)

    "firebase-admin": "~8.6.0",
    "firebase-functions": "^3.2.0",

@piotr-pawlowski
Copy link

Using the following dependencies fixed it for me (with node 10)

    "firebase-admin": "~8.6.0",
    "firebase-functions": "^3.2.0",

It doesn't work for me. Still receive that 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 ENOTFOUND metadata.google.internal metadata.google.internal:80. Error code: ENOTFOUND".

@aravindvnair99
Copy link
Contributor

GOOGLE_APPLICATION_CREDENTIALS=your_service_account.json firebase serve works for me as suggested by @samtstern but would be nice to have it work locally just as it works when deployed.

@vycoder
Copy link

vycoder commented Nov 22, 2020

I don't know if anyone else is dumb enough to try what I did,

But I fixed this issue by going to the Firebase console and creating a Service account from there instead of creating a Service account from the GCP IAM & Admin area. Then I initialized the project with:

var serviceAccount = require('./myproject-1234.json');

admin.initializeApp({
    projectId: 'myproject',
    credential: admin.credential.cert(serviceAccount),
});

Tried this one and it worked. Was using firebase-admin@8.10.0 and firebase-tools@8.16.2

@garyo
Copy link

garyo commented Feb 9, 2021

This is still happening for me, and is pretty annoying. Everything else works with ADC (GCE, Firestore, GCS, etc.) but for some reason auth doesn't, and this is considered to be "working as intended". I can't always set GOOGLE_APPLICATION_CREDENTIALS because that confuses some other things that need to use application-default credentials. So I'm forced to set it and unset it depending on which of my local admin tools I'm using! It's even more annoying because when I switch projects from dev to production it's just one more thing to have to remember to switch, and if it's silently out of sync from gcloud config get-value project then I can accidentally update the wrong dataset.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests