Skip to content

Commit 6a4953c

Browse files
committed
Add linking and reauth to email credential
1 parent 60bdff0 commit 6a4953c

File tree

3 files changed

+94
-28
lines changed

3 files changed

+94
-28
lines changed

packages-exp/auth-exp/src/api/authentication/email_link.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { Endpoint, HttpMethod, _performSignInRequest } from '..';
18+
import { _performSignInRequest, Endpoint, HttpMethod } from '../';
1919
import { Auth } from '../../model/auth';
2020
import { IdTokenResponse } from '../../model/id_token';
2121

@@ -38,3 +38,17 @@ export async function signInWithEmailLink(
3838
SignInWithEmailLinkResponse
3939
>(auth, HttpMethod.POST, Endpoint.SIGN_IN_WITH_EMAIL_LINK, request);
4040
}
41+
42+
export interface SignInWithEmailLinkForLinkingRequest extends SignInWithEmailLinkRequest {
43+
idToken: string;
44+
}
45+
46+
export async function signInWithEmailLinkForLinking(
47+
auth: Auth,
48+
request: SignInWithEmailLinkForLinkingRequest
49+
): Promise<SignInWithEmailLinkResponse> {
50+
return _performSignInRequest<
51+
SignInWithEmailLinkForLinkingRequest,
52+
SignInWithEmailLinkResponse
53+
>(auth, HttpMethod.POST, Endpoint.SIGN_IN_WITH_EMAIL_LINK, request);
54+
}

packages-exp/auth-exp/src/core/credentials/email.test.ts

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ describe('core/credentials/email', () => {
7575
});
7676

7777
describe('#_getIdTokenResponse', () => {
78-
it('call sign in with password', async () => {
78+
it('calls sign in with password', async () => {
7979
const idTokenResponse = await credential._getIdTokenResponse(auth);
8080
expect(idTokenResponse.idToken).to.eq('id-token');
8181
expect(idTokenResponse.refreshToken).to.eq('refresh-token');
@@ -90,18 +90,40 @@ describe('core/credentials/email', () => {
9090
});
9191

9292
describe('#_linkToIdToken', () => {
93-
it('throws', async () => {
94-
await expect(
95-
credential._linkToIdToken(auth, 'id-token')
96-
).to.be.rejectedWith(Error);
93+
it('calls update email password', async () => {
94+
apiMock = mockEndpoint(Endpoint.SET_ACCOUNT_INFO, {
95+
idToken: 'id-token',
96+
refreshToken: 'refresh-token',
97+
expiresIn: '1234',
98+
localId: serverUser.localId!
99+
});
100+
101+
const idTokenResponse = await credential._linkToIdToken(auth, 'id-token-2');
102+
expect(idTokenResponse.idToken).to.eq('id-token');
103+
expect(idTokenResponse.refreshToken).to.eq('refresh-token');
104+
expect(idTokenResponse.expiresIn).to.eq('1234');
105+
expect(idTokenResponse.localId).to.eq(serverUser.localId);
106+
expect(apiMock.calls[0].request).to.eql({
107+
idToken: 'id-token-2',
108+
returnSecureToken: true,
109+
email: 'some-email',
110+
password: 'some-password'
111+
});
97112
});
98113
});
99114

100115
describe('#_getReauthenticationResolver', () => {
101-
it('throws', () => {
102-
expect(() => credential._getReauthenticationResolver(auth)).to.throw(
103-
Error
104-
);
116+
it('calls sign in with password', async () => {
117+
const idTokenResponse = await credential._getIdTokenResponse(auth);
118+
expect(idTokenResponse.idToken).to.eq('id-token');
119+
expect(idTokenResponse.refreshToken).to.eq('refresh-token');
120+
expect(idTokenResponse.expiresIn).to.eq('1234');
121+
expect(idTokenResponse.localId).to.eq(serverUser.localId);
122+
expect(apiMock.calls[0].request).to.eql({
123+
returnSecureToken: true,
124+
email: 'some-email',
125+
password: 'some-password'
126+
});
105127
});
106128
});
107129
});
@@ -153,18 +175,31 @@ describe('core/credentials/email', () => {
153175
});
154176

155177
describe('#_linkToIdToken', () => {
156-
it('throws', async () => {
157-
await expect(
158-
credential._linkToIdToken(auth, 'id-token')
159-
).to.be.rejectedWith(Error);
178+
it('calls sign in with the new token', async () => {
179+
const idTokenResponse = await credential._linkToIdToken(auth, 'id-token-2');
180+
expect(idTokenResponse.idToken).to.eq('id-token');
181+
expect(idTokenResponse.refreshToken).to.eq('refresh-token');
182+
expect(idTokenResponse.expiresIn).to.eq('1234');
183+
expect(idTokenResponse.localId).to.eq(serverUser.localId);
184+
expect(apiMock.calls[0].request).to.eql({
185+
idToken: 'id-token-2',
186+
email: 'some-email',
187+
oobCode: 'oob-code'
188+
});
160189
});
161190
});
162191

163192
describe('#_matchIdTokenWithUid', () => {
164-
it('throws', () => {
165-
expect(() => credential._getReauthenticationResolver(auth)).to.throw(
166-
Error
167-
);
193+
it('call sign in with email link', async () => {
194+
const idTokenResponse = await credential._getIdTokenResponse(auth);
195+
expect(idTokenResponse.idToken).to.eq('id-token');
196+
expect(idTokenResponse.refreshToken).to.eq('refresh-token');
197+
expect(idTokenResponse.expiresIn).to.eq('1234');
198+
expect(idTokenResponse.localId).to.eq(serverUser.localId);
199+
expect(apiMock.calls[0].request).to.eql({
200+
email: 'some-email',
201+
oobCode: 'oob-code'
202+
});
168203
});
169204
});
170205
});

packages-exp/auth-exp/src/core/credentials/email.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@
1717

1818
import * as externs from '@firebase/auth-types-exp';
1919

20+
import { updateEmailPassword } from '../../api/account_management/email_and_password';
2021
import { signInWithPassword } from '../../api/authentication/email_and_password';
21-
import { signInWithEmailLink } from '../../api/authentication/email_link';
22+
import {
23+
signInWithEmailLink, signInWithEmailLinkForLinking
24+
} from '../../api/authentication/email_link';
2225
import { Auth } from '../../model/auth';
2326
import { IdTokenResponse } from '../../model/id_token';
24-
import { AUTH_ERROR_FACTORY, AuthErrorCode } from '../errors';
27+
import { AuthErrorCode } from '../errors';
2528
import { EmailAuthProvider } from '../providers/email';
26-
import { debugFail } from '../util/assert';
29+
import { debugFail, fail } from '../util/assert';
2730
import { AuthCredential } from './';
2831

2932
export class EmailAuthCredential implements AuthCredential {
@@ -57,17 +60,31 @@ export class EmailAuthCredential implements AuthCredential {
5760
oobCode: this.password
5861
});
5962
default:
60-
throw AUTH_ERROR_FACTORY.create(AuthErrorCode.INTERNAL_ERROR, {
61-
appName: auth.name
62-
});
63+
fail(auth.name, AuthErrorCode.INTERNAL_ERROR);
6364
}
6465
}
6566

66-
async _linkToIdToken(_auth: Auth, _idToken: string): Promise<never> {
67-
debugFail('Method not implemented.');
67+
async _linkToIdToken(auth: Auth, idToken: string): Promise<IdTokenResponse> {
68+
switch (this.signInMethod) {
69+
case EmailAuthProvider.EMAIL_PASSWORD_SIGN_IN_METHOD:
70+
return updateEmailPassword(auth, {
71+
idToken,
72+
returnSecureToken: true,
73+
email: this.email,
74+
password: this.password
75+
});
76+
case EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD:
77+
return signInWithEmailLinkForLinking(auth, {
78+
idToken,
79+
email: this.email,
80+
oobCode: this.password
81+
});
82+
default:
83+
fail(auth.name, AuthErrorCode.INTERNAL_ERROR);
84+
}
6885
}
6986

70-
_getReauthenticationResolver(_auth: Auth): Promise<never> {
71-
debugFail('Method not implemented.');
87+
_getReauthenticationResolver(auth: Auth): Promise<IdTokenResponse> {
88+
return this._getIdTokenResponse(auth);
7289
}
7390
}

0 commit comments

Comments
 (0)