Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Unreleased

-
- [changed] The `admin.initializeApp()` method can now be invoked without an
explicit `credential` option. In that case the SDK will get initialized with
Google application default credentials.

# v5.9.0

Expand Down
23 changes: 11 additions & 12 deletions src/firebase-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import {Credential, GoogleOAuthAccessToken} from './auth/credential';
import {ApplicationDefaultCredential, Credential, GoogleOAuthAccessToken} from './auth/credential';
import * as validator from './utils/validator';
import {deepCopy, deepExtend} from './utils/deep-copy';
import {FirebaseServiceInterface} from './firebase-service';
Expand Down Expand Up @@ -248,27 +248,26 @@ export class FirebaseApp {
this.name_ = name;
this.options_ = deepCopy(options) as FirebaseAppOptions;

if (typeof this.options_ !== 'object' || this.options_ === null) {
// Ensure the options are a non-null object
this.options_ = {};
if (!validator.isNonNullObject(this.options_)) {
throw new FirebaseAppError(
AppErrorCodes.INVALID_APP_OPTIONS,
`Invalid Firebase app options passed as the first argument to initializeApp() for the ` +
`app named "${this.name_}". Options must be a non-null object.`,
);
}

const hasCredential = ('credential' in this.options_);

let errorMessage: string;
if (!hasCredential) {
errorMessage = 'Options must be an object containing at least a "credential" property.';
this.options_.credential = new ApplicationDefaultCredential();
}

const credential = this.options_.credential;
if (typeof credential !== 'object' || credential === null || typeof credential.getAccessToken !== 'function') {
errorMessage = 'The "credential" property must be an object which implements the Credential interface.';
}

if (typeof errorMessage !== 'undefined') {
throw new FirebaseAppError(
AppErrorCodes.INVALID_APP_OPTIONS,
`Invalid Firebase app options passed as the first argument to initializeApp() for the ` +
`app named "${this.name_}". ${errorMessage}`,
`app named "${this.name_}". The "credential" property must be an object which implements ` +
`the Credential interface.`,
);
}

Expand Down
19 changes: 7 additions & 12 deletions test/unit/firebase.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import * as utils from './utils';
import * as mocks from '../resources/mocks';

import * as firebaseAdmin from '../../src/index';
import {ApplicationDefaultCredential} from '../../src/auth/credential';

chai.should();
chai.use(chaiAsPromised);
Expand Down Expand Up @@ -55,25 +56,19 @@ describe('Firebase', () => {
});

describe('#initializeApp()', () => {
const invalidOptions = [null, NaN, 0, 1, true, false, '', 'a', [], {}, _.noop];
invalidOptions.forEach((invalidOption) => {
const invalidOptions = [null, NaN, 0, 1, true, false, '', 'a', [], _.noop];
invalidOptions.forEach((invalidOption: any) => {
it('should throw given invalid options object: ' + JSON.stringify(invalidOption), () => {
expect(() => {
firebaseAdmin.initializeApp(invalidOption);
}).to.throw('Invalid Firebase app options');
});
});

it('should throw given an options object that does not contain any of the required keys', () => {
expect(() => {
firebaseAdmin.initializeApp({ a: 1, b: true } as any);
}).to.throw('Invalid Firebase app options');
});

it('should throw given an options object containing no "credential" key', () => {
expect(() => {
firebaseAdmin.initializeApp(mocks.appOptionsNoAuth);
}).to.throw('Invalid Firebase app options');
it('should use application default credentials when no credentials are explicitly specified', () => {
const app = firebaseAdmin.initializeApp(mocks.appOptionsNoAuth);
expect(app.options).to.have.property('credential');
expect(app.options.credential).to.be.instanceOf(ApplicationDefaultCredential);
});

it('should not modify the provided options object', () => {
Expand Down