Skip to content

fix(auth): Use 'owner' token when communicating with Auth emulator #1085

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

Merged
merged 10 commits into from
Nov 11, 2020

Conversation

samtstern
Copy link
Contributor

Hey there! So you want to contribute to a Firebase SDK?
Before you file this pull request, please read these guidelines:

Discussion

Fixes #1077

Testing

Wrote a simple test.js script:

const admin = require('firebase-admin');
admin.initializeApp({
  projectId: 'fir-dumpster'
});

async function main() {
  console.log(`FIREBASE_AUTH_EMULATOR_HOST=${process.env.FIREBASE_AUTH_EMULATOR_HOST}`);
  const user = await admin.auth().createUser({
    uid: "user" + new Date().getTime()
  });

  console.log("Created: ", user.uid)
}

main();

When executed as normal:

$ node test.js 
FIREBASE_AUTH_EMULATOR_HOST=undefined
(node:37745) 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 ENOTFOUND metadata.google.internal metadata.google.internal:80. Error code: ENOTFOUND".
    at FirebaseAppError.FirebaseError [as constructor] (/Users/samstern/Projects/firebase-admin-node/lib/utils/error.js:43:28)
    at FirebaseAppError.PrefixedFirebaseError [as constructor] (/Users/samstern/Projects/firebase-admin-node/lib/utils/error.js:89:28)
    at new FirebaseAppError (/Users/samstern/Projects/firebase-admin-node/lib/utils/error.js:124:28)
    at /Users/samstern/Projects/firebase-admin-node/lib/firebase-app.js:122:23
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:37745) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:37745) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

When executed in the emulators:

$ firebase emulators:exec "node test.js"
i  emulators: Starting emulators: auth, functions
⚠  functions: The following emulators are not running, calls to these services from the Functions emulator will affect production: firestore, database, hosting, pubsub
⚠  Your requested "node" version "12" doesn't match your global version "10"
i  functions: Watching "/private/var/folders/xl/6lkrzp7j07581mw8_4dlt3b000643s/T/tmp.35bA7OYr/functions" for Cloud Functions...
i  Running script: node test.js
FIREBASE_AUTH_EMULATOR_HOST=localhost:9099
Created:  user1604932585692
✔  Script exited successfully (code 0)
i  emulators: Shutting down emulators.
i  functions: Stopping Functions Emulator
i  auth: Stopping Authentication Emulator
i  hub: Stopping emulator hub

API Changes

N/A

Copy link
Contributor

@hiranya911 hiranya911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest a simpler implementation like the following:

  1. Change the AuthorizedHttpClient so child classes can override how it fetches tokens:
export class AuthorizedHttpClient extends HttpClient {
  constructor(private readonly app: FirebaseApp) {
    super();
  }

  protected getToken(): Promise<string> {
    return this.app.INTERNAL.getToken().then((result) => {
      return result.accessToken;
    });
  }

}
  1. Then in the Auth module extend the above class, and override getToken():
class AuthHttpClient extends AuthorizedHttpClient {
  constructor(app: FirebaseApp, private readonly useEmulator: boolean) {
    super(app);
  }

  protected getToken(): Promise<string> {
    if (this.useEmulator) {
      return Promise.resolve('owner');
    }

    return super.getToken();
  }
}

export abstract class AbstractAuthRequestHandler {
  constructor(protected readonly app: FirebaseApp, useEmulator: boolean) {
    this.httpClient = new AuthHttpClient(app, useEmulator); 
  }
}

@samtstern
Copy link
Contributor Author

@hiranya911 thanks for the comments! You're right that's much cleaner.

@samtstern samtstern requested a review from hiranya911 November 10, 2020 11:13
@samtstern samtstern assigned hiranya911 and unassigned samtstern Nov 10, 2020
Copy link
Contributor

@hiranya911 hiranya911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a suggestion.

@hiranya911 hiranya911 assigned samtstern and unassigned hiranya911 Nov 10, 2020
Copy link
Contributor

@hiranya911 hiranya911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, can I ask you to add some test cases for this change?

@bojeil-google bojeil-google removed their assignment Nov 11, 2020
@samtstern samtstern requested a review from hiranya911 November 11, 2020 13:59
@samtstern samtstern assigned hiranya911 and unassigned samtstern Nov 11, 2020
@samtstern samtstern dismissed bojeil-google’s stale review November 11, 2020 14:09

Hiranya and Bassam asked for the same things

Copy link
Contributor

@hiranya911 hiranya911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank! LGTM with a couple of nits.

@hiranya911 hiranya911 assigned samtstern and unassigned hiranya911 Nov 11, 2020
@hiranya911 hiranya911 changed the title Use 'owner' token when communicating with Auth emulator fix(auth): Use 'owner' token when communicating with Auth emulator Nov 11, 2020
@yuchenshi yuchenshi merged commit cb3d2c3 into master Nov 11, 2020
@nVitius
Copy link

nVitius commented Nov 11, 2020

I know this was merged very recently, but when can we expect to see this in a tagged release?

@samtstern
Copy link
Contributor Author

@nVitius we don't have a strict release cadence but if you look at the past we've released about once a month or so:
https://github.com/firebase/firebase-admin-node/releases

This change will be included in the next release. If you want to use it right now you can always clone the master branch of this GitHub repo and npm install the dependency locally!

@samtstern
Copy link
Contributor Author

@nVitius well you got lucky ... the 9.4.0 release with this fix went out!

BorntraegerMarc pushed a commit to BorntraegerMarc/firebase-admin-node that referenced this pull request Jan 28, 2021
* Use 'owner' token when communicating with Auth emulator

* Unused import

* Single quote

* Simplify to address code review

* Further simplify

* Reduce diff

* Stray comma

* Remove circular import, add unit test

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

Successfully merging this pull request may close these issues.

Error fetching access token. Not connecting to Firebase Auth Emulator if application_default_credentials.json not present
5 participants