Skip to content

Commit

Permalink
Add a way to specify emulator host/port for Auth (#3810)
Browse files Browse the repository at this point in the history
* Add a way to specify emulator host/port for Auth

* Update API to take URI instead of hostname/port

* Pull over more changes from internal repo

* Fix a couple emulator related issues

* Use window.emulatorURL for demo code

* Remove debugger statement

* Update packages/auth/src/auth.js

* PR Feedback + typings

* Add changeset

* Update packages/firebase/index.d.ts

Co-authored-by: Feiyang <[email protected]>

* Update .changeset/clean-toes-pump.md

Co-authored-by: Feiyang <[email protected]>

Co-authored-by: Sam Olsen <[email protected]>
Co-authored-by: Yuchen Shi <[email protected]>
Co-authored-by: Feiyang <[email protected]>
  • Loading branch information
4 people authored Oct 13, 2020
1 parent 8c0f1e2 commit eeb1dfa
Show file tree
Hide file tree
Showing 25 changed files with 1,539 additions and 133 deletions.
6 changes: 6 additions & 0 deletions .changeset/clean-toes-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@firebase/auth': minor
'firebase': minor
---

Add ability to configure the SDK to communicate with the Firebase Auth emulator.
2 changes: 1 addition & 1 deletion packages/auth/buildtools/run_demo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ cp ../firebase/firebase-auth.js demo/public/dist/firebase-auth.js
cp ../firebase/firebase-database.js demo/public/dist/firebase-database.js
# Serve demo app.
cd demo
`yarn bin`/firebase serve --only hosting,functions
`yarn bin`/firebase emulators:start
66 changes: 66 additions & 0 deletions packages/auth/demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
firebase-debug.log*
firebase-debug.*.log*

# Firebase cache
.firebase/

# Firebase config

# Uncomment this if you'd like others to create their own Firebase project.
# For a team working on the same Firebase project(s), it is recommended to leave
# it commented so all members can deploy to the same project(s) in .firebaserc.
# .firebaserc

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env
17 changes: 17 additions & 0 deletions packages/auth/demo/firebase.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,22 @@
"function": "checkIfAuthenticated"
}
]
},
"emulators": {
"auth": {
"port": 9099
},
"functions": {
"port": 5001
},
"database": {
"port": 9000
},
"hosting": {
"port": 5000
},
"ui": {
"enabled": true
}
}
}
3 changes: 3 additions & 0 deletions packages/auth/demo/public/sample-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ var config = {
storageBucket: "your-app.appspot.com",
messagingSenderId: "MESSAGING_SENDER_ID"
};

// Uncomment the following line to use with emulator
// var emulatorUrl = 'http://localhost:9099';
6 changes: 6 additions & 0 deletions packages/auth/demo/public/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -1623,12 +1623,18 @@ function initApp(){
log('Initializing app...');
app = firebase.initializeApp(config);
auth = app.auth();
if (window.emulatorUrl) {
auth.useEmulator(emulatorUrl);
}

tempApp = firebase.initializeApp({
'apiKey': config['apiKey'],
'authDomain': config['authDomain']
}, auth['app']['name'] + '-temp');
tempAuth = tempApp.auth();
if (window.emulatorUrl) {
tempAuth.useEmulator(emulatorUrl);
}

// Listen to reCAPTCHA config togglers.
initRecaptchaToggle(function(size) {
Expand Down
7 changes: 5 additions & 2 deletions packages/auth/demo/public/service-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ self.addEventListener('install', function(event) {
});

// As this is a test app, let's only return cached data when offline.
self.addEventListener('fetch', function(event) {
self.addEventListener('fetch', function (event) {
var fetchEvent = event;
var requestProcessor = function(idToken) {
var req = event.request;
Expand Down Expand Up @@ -154,7 +154,10 @@ self.addEventListener('fetch', function(event) {
event.respondWith(getIdToken().then(requestProcessor, requestProcessor));
});

self.addEventListener('activate', function(event) {
self.addEventListener('activate', function (event) {
if (window.emulatorUrl) {
firebase.auth().useEmulator(emulatorUrl);
}
// Update this list with all caches that need to remain cached.
var cacheWhitelist = ['cache-v1'];
event.waitUntil(caches.keys().then(function(cacheNames) {
Expand Down
1 change: 1 addition & 0 deletions packages/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@firebase/auth-types": "0.10.1"
},
"devDependencies": {
"firebase-tools": "8.11.2",
"google-closure-compiler": "20200112.0.0",
"google-closure-library": "20200224.0.0",
"gulp": "4.0.2",
Expand Down
135 changes: 130 additions & 5 deletions packages/auth/src/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,12 @@ fireauth.Auth = function(app) {
* is currently only used to log FirebaseUI.
*/
this.frameworks_ = [];

/**
* @private {?fireauth.constants.EmulatorSettings} The current
* emulator settings.
*/
this.emulatorConfig_ = null;
};
goog.inherits(fireauth.Auth, goog.events.EventTarget);

Expand All @@ -202,6 +208,20 @@ fireauth.Auth.LanguageCodeChangeEvent = function(languageCode) {
goog.inherits(fireauth.Auth.LanguageCodeChangeEvent, goog.events.Event);


/**
* Emulator config change custom event.
* @param {?fireauth.constants.EmulatorSettings} emulatorConfig The new
* emulator settings.
* @constructor
* @extends {goog.events.Event}
*/
fireauth.Auth.EmulatorConfigChangeEvent = function(emulatorConfig) {
goog.events.Event.call(this, fireauth.constants.AuthEventType.EMULATOR_CONFIG_CHANGED);
this.emulatorConfig = emulatorConfig;
};
goog.inherits(fireauth.Auth.EmulatorConfigChangeEvent, goog.events.Event);


/**
* Framework change custom event.
* @param {!Array<string>} frameworks The new frameworks array.
Expand Down Expand Up @@ -272,6 +292,65 @@ fireauth.Auth.prototype.useDeviceLanguage = function() {
};


/**
* Sets the emulator configuration (go/firebase-emulator-connection-api).
* @param {string} url The url for the Auth emulator.
*/
fireauth.Auth.prototype.useEmulator = function(url) {
// Emulator config can only be set once.
if (!this.emulatorConfig_) {
// Emit a warning so dev knows we are now in test mode.
this.emitEmulatorWarning_();
// Persist the config.
this.emulatorConfig_ = { url };
// Disable app verification.
this.settings_().setAppVerificationDisabledForTesting(true);
// Update RPC handler endpoints.
this.rpcHandler_.updateEmulatorConfig(this.emulatorConfig_);
// Notify external event listeners.
this.notifyEmulatorConfigListeners_();
}
}


/**
* Emits a console warning and a visual banner if emulator integration is
* enabled.
*/
fireauth.Auth.prototype.emitEmulatorWarning_ = function() {
fireauth.util.consoleWarn('WARNING: You are using the Auth Emulator,' +
' which is intended for local testing only. Do not use with' +
' production credentials.');
if (goog.global.document) {
fireauth.util.onDomReady().then(() => {
const ele = goog.global.document.createElement('div');
ele.innerText = 'Running in emulator mode. Do not use with production' +
' credentials.';
ele.style.position = 'fixed';
ele.style.width = '100%';
ele.style.backgroundColor = '#ffffff';
ele.style.border = '.1em solid #000000';
ele.style.color = '#ff0000';
ele.style.bottom = '0px';
ele.style.left = '0px';
ele.style.margin = '0px';
ele.style.zIndex = 10000;
ele.style.textAlign = 'center';
ele.classList.add('firebase-emulator-warning');
goog.global.document.body.appendChild(ele);
});
}
}


/**
* @return {?fireauth.constants.EmulatorSettings}
*/
fireauth.Auth.prototype.getEmulatorConfig = function() {
return this.emulatorConfig_;
}


/**
* @param {string} frameworkId The framework identifier.
*/
Expand Down Expand Up @@ -396,7 +475,15 @@ fireauth.Auth.prototype.notifyLanguageCodeListeners_ = function() {
};



/**
* Notifies all external listeners of the emulator config change.
* @private
*/
fireauth.Auth.prototype.notifyEmulatorConfigListeners_ = function() {
// Notify external listeners on the emulator config change.
this.dispatchEvent(
new fireauth.Auth.EmulatorConfigChangeEvent(this.emulatorConfig_));
}


/**
Expand Down Expand Up @@ -449,7 +536,10 @@ fireauth.Auth.prototype.initAuthEventManager_ = function() {
// By this time currentUser should be ready if available and will be able
// to resolve linkWithRedirect if detected.
self.authEventManager_ = fireauth.AuthEventManager.getManager(
authDomain, apiKey, self.app_().name);
authDomain,
apiKey,
self.app_().name,
self.emulatorConfig_);
// Subscribe Auth instance.
self.authEventManager_.subscribe(self);
// Subscribe current user by enabling popup and redirect on that user.
Expand All @@ -471,7 +561,10 @@ fireauth.Auth.prototype.initAuthEventManager_ = function() {
/** @type {!fireauth.AuthUser} */ (self.redirectUser_));
// Set the user Firebase frameworks for the redirect user.
self.setUserFramework_(
/** @type {!fireauth.AuthUser} */ (self.redirectUser_));
/** @type {!fireauth.AuthUser} */(self.redirectUser_));
// Set the user Emulator configuration for the redirect user.
self.setUserEmulatorConfig_(
/** @type {!fireauth.AuthUser} */(self.redirectUser_));
// Reference to redirect user no longer needed.
self.redirectUser_ = null;
}
Expand Down Expand Up @@ -650,7 +743,8 @@ fireauth.Auth.prototype.signInWithPopup = function(provider) {
firebase.SDK_VERSION || null,
null,
null,
this.getTenantId());
this.getTenantId(),
this.emulatorConfig_);
}
// The popup must have a name, otherwise when successive popups are triggered
// they will all render in the same instance and none will succeed since the
Expand Down Expand Up @@ -856,6 +950,9 @@ fireauth.Auth.prototype.signInWithIdTokenResponse =
options['apiKey'] = self.app_().options['apiKey'];
options['authDomain'] = self.app_().options['authDomain'];
options['appName'] = self.app_().name;
if (self.emulatorConfig_) {
options['emulatorConfig'] = self.emulatorConfig_;
}
// Wait for state to be ready.
// This is used internally and is also used for redirect sign in so there is
// no need for waiting for redirect result to resolve since redirect result
Expand Down Expand Up @@ -911,6 +1008,9 @@ fireauth.Auth.prototype.setCurrentUser_ = function(user) {
// Set the current frameworks used on the user and set current Auth instance
// as the framework change dispatcher.
this.setUserFramework_(user);
// If a user is available, set the emulator config on it and set current
// Auth instance as emulator config change dispatcher.
this.setUserEmulatorConfig_(user);
}
};

Expand Down Expand Up @@ -1001,7 +1101,7 @@ fireauth.Auth.prototype.initAuthState_ = function() {
var p = this.initRedirectUser_().then(function() {
// Override user's authDomain with app's authDomain if there is a mismatch.
return /** @type {!fireauth.storage.UserManager} */ (
self.userStorageManager_).getCurrentUser(authDomain);
self.userStorageManager_).getCurrentUser(authDomain, self.emulatorConfig_);
}).then(function(user) {
// Logged in user.
if (user) {
Expand Down Expand Up @@ -1179,6 +1279,22 @@ fireauth.Auth.prototype.setUserLanguage_ = function(user) {
};


/**
* Updates the emulator config on the provided user and configures the user
* to listen to the Auth instance for any emulator config changes.
* @param {!fireauth.AuthUser} user The user to whose emulator config needs
* to be set.
* @private
*/
fireauth.Auth.prototype.setUserEmulatorConfig_ = function(user) {
// Sets the current emulator config on the user.
user.setEmulatorConfig(this.emulatorConfig_);
// Sets current Auth instance as emulator config change dispatcher on the
// user.
user.setEmulatorConfigChangeDispatcher(this);
}


/**
* Handles user state changes.
* @param {!fireauth.AuthUser} user The user which triggered the state changes.
Expand Down Expand Up @@ -1679,6 +1795,15 @@ fireauth.Auth.prototype.app_ = function() {
};


/**
* @return {!fireauth.AuthSettings} The settings for this Auth object.
* @private
*/
fireauth.Auth.prototype.settings_ = function () {
return this['settings'];
};


/**
* @return {!fireauth.RpcHandler} The RPC handler.
*/
Expand Down
Loading

0 comments on commit eeb1dfa

Please sign in to comment.