Skip to content

Commit e658eed

Browse files
committed
Handle anonymous auth re-login edge case
1 parent 959e21a commit e658eed

File tree

2 files changed

+94
-14
lines changed

2 files changed

+94
-14
lines changed

packages-exp/auth-exp/src/core/user/additional_user_info.test.ts

Lines changed: 82 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,26 @@
1717

1818
import { expect } from 'chai';
1919

20-
import { ProviderId, UserProfile } from '@firebase/auth-types-exp';
20+
import { OperationType, ProviderId, UserProfile } from '@firebase/auth-types-exp';
2121

2222
import { IdTokenResponse, IdTokenResponseKind } from '../../model/id_token';
23-
import { _fromIdTokenResponse } from './additional_user_info';
23+
import { _fromIdTokenResponse, getAdditionalUserInfo } from './additional_user_info';
2424
import { base64Encode } from '@firebase/util';
25+
import { UserCredentialImpl } from './user_credential_impl';
26+
import { Auth } from '../../model/auth';
27+
import { User, UserCredential } from '../../model/user';
28+
import { testAuth, testUser } from '../../../test/helpers/mock_auth';
2529

2630
describe('core/user/additional_user_info', () => {
31+
const userProfileWithLogin: UserProfile = {
32+
login: 'scott',
33+
friends: [],
34+
netWorth: 5.0
35+
};
36+
const rawUserInfoWithLogin = JSON.stringify(userProfileWithLogin);
37+
const userProfileNoLogin: UserProfile = { sample: 'data' };
38+
const rawUserInfoNoLogin = JSON.stringify(userProfileNoLogin);
2739
describe('_fromIdTokenResponse', () => {
28-
const userProfileWithLogin: UserProfile = {
29-
login: 'scott',
30-
friends: [],
31-
netWorth: 5.0
32-
};
33-
const rawUserInfoWithLogin = JSON.stringify(userProfileWithLogin);
34-
const userProfileNoLogin: UserProfile = { sample: 'data' };
35-
const rawUserInfoNoLogin = JSON.stringify(userProfileNoLogin);
36-
3740
describe('parses federated IDP response tokens', () => {
3841
it('for FacebookAdditionalUserInfo', () => {
3942
const idResponse = idTokenResponse({
@@ -211,6 +214,74 @@ describe('core/user/additional_user_info', () => {
211214
});
212215
});
213216
});
217+
218+
describe('getAdditionalUserInfo()', () => {
219+
let auth: Auth;
220+
let user: User;
221+
let cred: UserCredential;
222+
beforeEach(async () => {
223+
auth = await testAuth();
224+
user = testUser(auth, 'uid');
225+
cred = new UserCredentialImpl({
226+
user,
227+
providerId: null,
228+
operationType: OperationType.SIGN_IN,
229+
});
230+
});
231+
232+
it('calls through to _fromIdTokenResponse', () => {
233+
cred._tokenResponse = idTokenResponse({
234+
providerId: ProviderId.ANONYMOUS,
235+
rawUserInfo: rawUserInfoWithLogin
236+
});
237+
const {
238+
isNewUser,
239+
providerId,
240+
username,
241+
profile
242+
} = getAdditionalUserInfo(cred)!;
243+
expect(isNewUser).to.be.false;
244+
expect(providerId).to.be.null;
245+
expect(username).to.be.undefined;
246+
expect(profile).to.eq(profile);
247+
});
248+
249+
it('calls through to _fromIdTokenResponse preserving isNewUser', () => {
250+
cred._tokenResponse = idTokenResponse({
251+
providerId: ProviderId.ANONYMOUS,
252+
rawUserInfo: rawUserInfoWithLogin,
253+
isNewUser: true
254+
});
255+
const {
256+
isNewUser,
257+
providerId,
258+
username,
259+
profile
260+
} = getAdditionalUserInfo(cred)!;
261+
expect(isNewUser).to.be.true;
262+
expect(providerId).to.be.null;
263+
expect(username).to.be.undefined;
264+
expect(profile).to.eq(profile);
265+
});
266+
267+
it('returns bespoke info if existing anonymous user', () => {
268+
// Note that _tokenResponse is not set on cred
269+
(user as unknown as Record<string, unknown>).isAnonymous = true;
270+
const {
271+
isNewUser,
272+
providerId,
273+
profile
274+
} = getAdditionalUserInfo(cred)!;
275+
expect(isNewUser).to.be.false;
276+
expect(providerId).to.be.null;
277+
expect(profile).to.eq(profile);
278+
});
279+
280+
it('returns null if not anonymous', () => {
281+
// Note that _tokenResponse is not set on cred
282+
expect(getAdditionalUserInfo(cred)).to.be.null;
283+
});
284+
});
214285
});
215286

216287
function idTokenResponse(partial: Partial<IdTokenResponse>): IdTokenResponse {

packages-exp/auth-exp/src/core/user/additional_user_info.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,16 @@ class TwitterAdditionalUserInfo extends FederatedAdditionalUserInfoWithUsername
129129
export function getAdditionalUserInfo(
130130
userCredential: externs.UserCredential
131131
): externs.AdditionalUserInfo | null {
132-
return _fromIdTokenResponse(
133-
(userCredential as UserCredential)._tokenResponse
134-
);
132+
const {user, _tokenResponse} = userCredential as UserCredential;
133+
if (user.isAnonymous && !_tokenResponse) {
134+
// Handle the special case where signInAnonymously() gets called twice.
135+
// No network call is made so there's nothing to actually fill this in
136+
return {
137+
providerId: null,
138+
isNewUser: false,
139+
profile: null,
140+
};
141+
}
142+
143+
return _fromIdTokenResponse(_tokenResponse);
135144
}

0 commit comments

Comments
 (0)