diff --git a/packages/auth/src/api/account_management/email_and_password.test.ts b/packages/auth/src/api/account_management/email_and_password.test.ts index e5268860b47..44af356cfd3 100644 --- a/packages/auth/src/api/account_management/email_and_password.test.ts +++ b/packages/auth/src/api/account_management/email_and_password.test.ts @@ -27,6 +27,7 @@ import * as mockFetch from '../../../test/helpers/mock_fetch'; import { ServerError } from '../errors'; import { applyActionCode, + linkEmailPassword, resetPassword, updateEmailPassword } from './email_and_password'; @@ -91,6 +92,65 @@ describe('api/account_management/resetPassword', () => { }); }); +describe('api/account_management/linkEmailPassword', () => { + const request = { + idToken: 'id-token', + returnSecureToken: true, + email: 'test@foo.com', + password: 'new-password' + }; + + let auth: TestAuth; + + beforeEach(async () => { + auth = await testAuth(); + mockFetch.setUp(); + }); + + afterEach(mockFetch.tearDown); + + it('should POST to the correct endpoint', async () => { + const mock = mockEndpoint(Endpoint.SIGN_UP, { + idToken: 'id-token' + }); + + const response = await linkEmailPassword(auth, request); + expect(response.idToken).to.eq('id-token'); + expect(mock.calls[0].request).to.eql(request); + expect(mock.calls[0].method).to.eq('POST'); + expect(mock.calls[0].headers!.get(HttpHeader.CONTENT_TYPE)).to.eq( + 'application/json' + ); + expect(mock.calls[0].headers!.get(HttpHeader.X_CLIENT_VERSION)).to.eq( + 'testSDK/0.0.0' + ); + }); + + it('should handle errors', async () => { + const mock = mockEndpoint( + Endpoint.SIGN_UP, + { + error: { + code: 400, + message: ServerError.INVALID_EMAIL, + errors: [ + { + message: ServerError.INVALID_EMAIL + } + ] + } + }, + 400 + ); + + await expect(linkEmailPassword(auth, request)).to.be.rejectedWith( + FirebaseError, + 'Firebase: The email address is badly formatted. (auth/invalid-email).' + ); + expect(mock.calls[0].request).to.eql(request); + }); +}); + describe('api/account_management/updateEmailPassword', () => { const request = { idToken: 'id-token', diff --git a/packages/auth/src/api/account_management/email_and_password.ts b/packages/auth/src/api/account_management/email_and_password.ts index 7d6f4ab84c8..a2429659b30 100644 --- a/packages/auth/src/api/account_management/email_and_password.ts +++ b/packages/auth/src/api/account_management/email_and_password.ts @@ -69,6 +69,18 @@ export async function updateEmailPassword( >(auth, HttpMethod.POST, Endpoint.SET_ACCOUNT_INFO, request); } +// Used for linking an email/password account to an existing idToken. Uses the same request/response +// format as updateEmailPassword. +export async function linkEmailPassword( + auth: Auth, + request: UpdateEmailPasswordRequest +): Promise { + return _performApiRequest< + UpdateEmailPasswordRequest, + UpdateEmailPasswordResponse + >(auth, HttpMethod.POST, Endpoint.SIGN_UP, request); +} + export interface ApplyActionCodeRequest { oobCode: string; tenantId?: string; diff --git a/packages/auth/src/core/credentials/email.test.ts b/packages/auth/src/core/credentials/email.test.ts index f3e6ae4966f..74d7cba94b3 100644 --- a/packages/auth/src/core/credentials/email.test.ts +++ b/packages/auth/src/core/credentials/email.test.ts @@ -288,8 +288,8 @@ describe('core/credentials/email', () => { }); describe('#_linkToIdToken', () => { - it('calls update email password', async () => { - apiMock = mockEndpoint(Endpoint.SET_ACCOUNT_INFO, { + it('calls sign up with email password', async () => { + apiMock = mockEndpoint(Endpoint.SIGN_UP, { idToken: 'id-token', refreshToken: 'refresh-token', expiresIn: '1234', diff --git a/packages/auth/src/core/credentials/email.ts b/packages/auth/src/core/credentials/email.ts index 6421f33b5a1..69c4c119628 100644 --- a/packages/auth/src/core/credentials/email.ts +++ b/packages/auth/src/core/credentials/email.ts @@ -17,7 +17,10 @@ import { ProviderId, SignInMethod } from '../../model/enums'; -import { updateEmailPassword } from '../../api/account_management/email_and_password'; +import { + linkEmailPassword, + updateEmailPassword +} from '../../api/account_management/email_and_password'; import { signInWithPassword, SignInWithPasswordRequest @@ -166,7 +169,7 @@ export class EmailAuthCredential extends AuthCredential { ): Promise { switch (this.signInMethod) { case SignInMethod.EMAIL_PASSWORD: - return updateEmailPassword(auth, { + return linkEmailPassword(auth, { idToken, returnSecureToken: true, email: this._email,