diff --git a/etc/firebase-admin.auth.api.md b/etc/firebase-admin.auth.api.md index c7090af304..8679c64df9 100644 --- a/etc/firebase-admin.auth.api.md +++ b/etc/firebase-admin.auth.api.md @@ -73,7 +73,9 @@ export abstract class BaseAuth { createCustomToken(uid: string, developerClaims?: object): Promise; createProviderConfig(config: AuthProviderConfig): Promise; createSessionCookie(idToken: string, sessionCookieOptions: SessionCookieOptions): Promise; - createUser(properties: CreateRequest): Promise; + createUser(properties: CreateRequest, noFetchUserRecord?: boolean): Promise; + // (undocumented) + createUser(properties: CreateRequest, noFetchUserRecord: true): Promise; deleteProviderConfig(providerId: string): Promise; deleteUser(uid: string): Promise; deleteUsers(uids: string[]): Promise; @@ -93,7 +95,9 @@ export abstract class BaseAuth { revokeRefreshTokens(uid: string): Promise; setCustomUserClaims(uid: string, customUserClaims: object | null): Promise; updateProviderConfig(providerId: string, updatedConfig: UpdateAuthProviderRequest): Promise; - updateUser(uid: string, properties: UpdateRequest): Promise; + updateUser(uid: string, properties: UpdateRequest, noFetchUserRecord?: boolean): Promise; + // (undocumented) + updateUser(uid: string, properties: UpdateRequest, noFetchUserRecord: true): Promise; // @alpha (undocumented) _verifyAuthBlockingToken(token: string, audience?: string): Promise; verifyIdToken(idToken: string, checkRevoked?: boolean): Promise; diff --git a/src/auth/base-auth.ts b/src/auth/base-auth.ts index 6f77e088f8..a48c532d42 100644 --- a/src/auth/base-auth.ts +++ b/src/auth/base-auth.ts @@ -413,15 +413,24 @@ export abstract class BaseAuth { * * @param properties - The properties to set on the * new user record to be created. + * + * @param noFetchUserRecord - Defaults to `false` so that the updated + * user record will be fetched from the backend as a separate operation and returned. + * If `true`, then the updated user will not be fetched and will return `undefined`. * * @returns A promise fulfilled with the user - * data corresponding to the newly created user. + * data corresponding to the newly created user, + * or fulfilled with`undefined` if `noFetchUserRecord` was true. */ - public createUser(properties: CreateRequest): Promise { + public createUser(properties: CreateRequest, noFetchUserRecord?: boolean): Promise + public createUser(properties: CreateRequest, noFetchUserRecord: true): Promise + public createUser(properties: CreateRequest, noFetchUserRecord = false): Promise { return this.authRequestHandler.createNewAccount(properties) .then((uid) => { - // Return the corresponding user record. - return this.getUser(uid); + if (!noFetchUserRecord) { + // Return the corresponding user record. + return this.getUser(uid); + } }) .catch((error) => { if (error.code === 'auth/user-not-found') { @@ -527,11 +536,17 @@ export abstract class BaseAuth { * @param uid - The `uid` corresponding to the user to update. * @param properties - The properties to update on * the provided user. + * @param noFetchUserRecord - Defaults to `false` so that the updated + * user record will be fetched from the backend as a separate operation and returned. + * If `true`, then the updated user will not be fetched and will return `undefined`. * * @returns A promise fulfilled with the - * updated user data. + * updated user data, + * or fulfilled with`undefined` if `noFetchUserRecord` was true. */ - public updateUser(uid: string, properties: UpdateRequest): Promise { + public updateUser(uid: string, properties: UpdateRequest, noFetchUserRecord?: boolean): Promise + public updateUser(uid: string, properties: UpdateRequest, noFetchUserRecord: true): Promise + public updateUser(uid: string, properties: UpdateRequest, noFetchUserRecord = false): Promise { // Although we don't really advertise it, we want to also handle linking of // non-federated idps with this call. So if we detect one of them, we'll // adjust the properties parameter appropriately. This *does* imply that a @@ -578,8 +593,10 @@ export abstract class BaseAuth { return this.authRequestHandler.updateExistingAccount(uid, properties) .then((existingUid) => { - // Return the corresponding user record. - return this.getUser(existingUid); + if (!noFetchUserRecord) { + // Return the corresponding user record. + return this.getUser(existingUid); + } }); } diff --git a/test/unit/auth/auth.spec.ts b/test/unit/auth/auth.spec.ts index 4924cb5b12..0f34ef3533 100644 --- a/test/unit/auth/auth.spec.ts +++ b/test/unit/auth/auth.spec.ts @@ -1772,6 +1772,26 @@ AUTH_CONFIGS.forEach((testConfig) => { }); }); + it('should resolve with undefined on createNewAccount request success with noFetchUserRecord == true', () => { + // Stub createNewAccount to return expected uid. + const createUserStub = sinon.stub(testConfig.RequestHandler.prototype, 'createNewAccount') + .resolves(uid); + // Stub getAccountInfoByUid to return expected result. + const getUserStub = sinon.stub(testConfig.RequestHandler.prototype, 'getAccountInfoByUid') + .resolves(expectedGetAccountInfoResult); + stubs.push(createUserStub); + stubs.push(getUserStub); + return auth.createUser(propertiesToCreate, true) + .then((resp) => { + // Confirm underlying API called with expected parameters. + // getUser should NOT be called + expect(createUserStub).to.have.been.calledOnce.and.calledWith(propertiesToCreate); + expect(getUserStub).not.to.have.been.called; + // Confirm expected user record response returned. + expect(resp).to.be.undefined; + }); + }); + it('should throw an error when createNewAccount returns an error', () => { // Stub createNewAccount to throw a backend error. const createUserStub = sinon.stub(testConfig.RequestHandler.prototype, 'createNewAccount') @@ -2218,6 +2238,26 @@ AUTH_CONFIGS.forEach((testConfig) => { }); }); + it('should resolve with undefined on updateExistingAccount request success with noFetchUserRecord=true', () => { + // Stub updateExistingAccount to return expected uid. + const updateUserStub = sinon.stub(testConfig.RequestHandler.prototype, 'updateExistingAccount') + .resolves(uid); + // Stub getAccountInfoByUid to return expected result. + const getUserStub = sinon.stub(testConfig.RequestHandler.prototype, 'getAccountInfoByUid') + .resolves(expectedGetAccountInfoResult); + stubs.push(updateUserStub); + stubs.push(getUserStub); + return auth.updateUser(uid, propertiesToEdit, true) + .then((resp) => { + // Confirm underlying API called with expected parameters. + // getUser should NOT be called + expect(updateUserStub).to.have.been.calledOnce.and.calledWith(uid, propertiesToEdit); + expect(getUserStub).not.to.have.been.called; + // Confirm expected user record response returned. + expect(resp).to.be.undefined; + }); + }); + it('should throw an error when updateExistingAccount returns an error', () => { // Stub updateExistingAccount to throw a backend error. const updateUserStub = sinon.stub(testConfig.RequestHandler.prototype, 'updateExistingAccount')