Skip to content

Commit a49c51c

Browse files
authored
Fix some incorrect typings / missing pieces in the new auth SDK (#4187)
* Fix incorrect type for setPersistence, add missing static methods to OAuthCredential * Formatting * api review * Fix the signature of getAuth / initializeAuth * Fix tests
1 parent 7f7f507 commit a49c51c

File tree

10 files changed

+186
-13
lines changed

10 files changed

+186
-13
lines changed

common/api-review/auth-exp.api.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ export function fetchSignInMethodsForEmail(auth: externs.Auth, email: string): P
146146
export function getAdditionalUserInfo(userCredential: externs.UserCredential): externs.AdditionalUserInfo | null;
147147

148148
// @public
149-
export function getAuth(app?: FirebaseApp): Auth;
149+
export function getAuth(app: FirebaseApp): Auth;
150150

151151
// @public
152152
export function getIdToken(user: externs.User, forceRefresh?: boolean): Promise<string>;
@@ -186,7 +186,7 @@ export const indexedDBLocalPersistence: externs.Persistence;
186186
// Warning: (ae-forgotten-export) The symbol "Dependencies" needs to be exported by the entry point index.d.ts
187187
//
188188
// @public (undocumented)
189-
export function initializeAuth(app?: FirebaseApp, deps?: Dependencies): externs.Auth;
189+
export function initializeAuth(app: FirebaseApp, deps?: Dependencies): externs.Auth;
190190

191191
// @public
192192
export const inMemoryPersistence: externs.Persistence;
@@ -247,8 +247,10 @@ export class OAuthProvider implements externs.AuthProvider {
247247
constructor(providerId: string);
248248
addScope(scope: string): externs.AuthProvider;
249249
credential(params: OAuthCredentialOptions): externs.OAuthCredential;
250+
static credentialFromError(error: FirebaseError): externs.OAuthCredential | null;
250251
// (undocumented)
251252
static credentialFromJSON(json: object | string): externs.OAuthCredential;
253+
static credentialFromResult(userCredential: externs.UserCredential): externs.OAuthCredential | null;
252254
// @internal (undocumented)
253255
defaultLanguageCode: string | null;
254256
getCustomParameters(): CustomParameters;
@@ -363,7 +365,7 @@ export function sendPasswordResetEmail(auth: externs.Auth, email: string, action
363365
export function sendSignInLinkToEmail(auth: externs.Auth, email: string, actionCodeSettings?: externs.ActionCodeSettings): Promise<void>;
364366

365367
// @public
366-
export function setPersistence(auth: externs.Auth, persistence: externs.Persistence): void;
368+
export function setPersistence(auth: externs.Auth, persistence: externs.Persistence): Promise<void>;
367369

368370
// @public
369371
export function signInAnonymously(auth: externs.Auth): Promise<externs.UserCredential>;

packages-exp/auth-exp/index.node.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ FetchProvider.initialize(
4242
// Core functionality shared by all clients
4343
export * from './src';
4444

45-
export function getAuth(app?: FirebaseApp): Auth {
45+
export function getAuth(app: FirebaseApp): Auth {
4646
return initializeAuth(app);
4747
}
4848

packages-exp/auth-exp/index.rn.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export const reactNativeLocalPersistence = getReactNativePersistence(
3939
AsyncStorage
4040
);
4141

42-
export function getAuth(app?: FirebaseApp): Auth {
42+
export function getAuth(app: FirebaseApp): Auth {
4343
return initializeAuth(app, {
4444
persistence: reactNativeLocalPersistence
4545
});

packages-exp/auth-exp/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ export { PhoneMultiFactorGenerator } from './src/platform_browser/mfa/assertions
7070
*
7171
* @public
7272
*/
73-
export function getAuth(app?: FirebaseApp): Auth {
73+
export function getAuth(app: FirebaseApp): Auth {
7474
return initializeAuth(app, {
7575
popupRedirectResolver: browserPopupRedirectResolver,
7676
persistence: [indexedDBLocalPersistence, browserLocalPersistence]

packages-exp/auth-exp/index.webworker.ts

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

18-
import { _getProvider, getApp } from '@firebase/app-exp';
18+
import { _getProvider } from '@firebase/app-exp';
19+
import { FirebaseApp } from '@firebase/app-types-exp';
1920
import { Auth } from '@firebase/auth-types-exp';
2021

2122
import { AuthImpl } from './src/core/auth/auth_impl';
@@ -34,7 +35,7 @@ export { indexedDBLocalPersistence } from './src/platform_browser/persistence/in
3435

3536
registerAuth(ClientPlatform.WORKER);
3637

37-
export function getAuth(app = getApp()): Auth {
38+
export function getAuth(app: FirebaseApp): Auth {
3839
// Unlike the other environments, we need to explicitly check if indexedDb is
3940
// available. That means doing the whole rigamarole
4041
const auth = _getProvider(

packages-exp/auth-exp/src/core/auth/initialize.ts

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

18-
import { _getProvider, getApp } from '@firebase/app-exp';
18+
import { _getProvider } from '@firebase/app-exp';
1919
import { FirebaseApp } from '@firebase/app-types-exp';
2020
import * as externs from '@firebase/auth-types-exp';
2121

@@ -26,7 +26,7 @@ import { AuthImpl } from './auth_impl';
2626

2727
/** @public */
2828
export function initializeAuth(
29-
app: FirebaseApp = getApp(),
29+
app: FirebaseApp,
3030
deps?: Dependencies
3131
): externs.Auth {
3232
const auth = _getProvider(app, 'auth-exp').getImmediate() as AuthImpl;

packages-exp/auth-exp/src/core/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@ export { debugErrorMap, prodErrorMap } from './errors';
3838
*
3939
* @param auth - The Auth instance.
4040
* @param persistence - The {@link @firebase/auth-types#Persistence} to use.
41+
* @returns A promise that resolves once the persistence change has completed
4142
*
4243
* @public
4344
*/
4445
export function setPersistence(
4546
auth: externs.Auth,
4647
persistence: externs.Persistence
47-
): void {
48-
auth.setPersistence(persistence);
48+
): Promise<void> {
49+
return auth.setPersistence(persistence);
4950
}
5051
/**
5152
* Adds an observer for changes to the signed-in user's ID token, which includes sign-in,
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { expect } from 'chai';
19+
20+
import {
21+
OperationType,
22+
ProviderId,
23+
SignInMethod
24+
} from '@firebase/auth-types-exp';
25+
26+
import { TEST_ID_TOKEN_RESPONSE } from '../../../test/helpers/id_token_response';
27+
import { testUser, testAuth } from '../../../test/helpers/mock_auth';
28+
import { TaggedWithTokenResponse } from '../../model/id_token';
29+
import { AuthErrorCode } from '../errors';
30+
import { UserCredentialImpl } from '../user/user_credential_impl';
31+
import { _createError } from '../util/assert';
32+
import { OAuthProvider } from './oauth';
33+
34+
describe('core/providers/oauth', () => {
35+
it('generates the correct type of oauth credential', () => {
36+
const cred = new OAuthProvider('google.com').credential({
37+
idToken: 'id-token',
38+
accessToken: 'access-token'
39+
});
40+
expect(cred.accessToken).to.eq('access-token');
41+
expect(cred.idToken).to.eq('id-token');
42+
expect(cred.providerId).to.eq(ProviderId.GOOGLE);
43+
expect(cred.signInMethod).to.eq(SignInMethod.GOOGLE);
44+
});
45+
46+
it('credentialFromResult creates the cred from a tagged result', async () => {
47+
const auth = await testAuth();
48+
const userCred = new UserCredentialImpl({
49+
user: testUser(auth, 'uid'),
50+
providerId: ProviderId.GOOGLE,
51+
_tokenResponse: {
52+
...TEST_ID_TOKEN_RESPONSE,
53+
oauthAccessToken: 'access-token',
54+
oauthIdToken: 'id-token',
55+
providerId: ProviderId.FACEBOOK
56+
},
57+
operationType: OperationType.SIGN_IN
58+
});
59+
const cred = OAuthProvider.credentialFromResult(userCred)!;
60+
expect(cred.accessToken).to.eq('access-token');
61+
expect(cred.idToken).to.eq('id-token');
62+
expect(cred.providerId).to.eq(ProviderId.FACEBOOK);
63+
expect(cred.signInMethod).to.eq(SignInMethod.FACEBOOK);
64+
});
65+
66+
it('credentialFromResult returns null if provider ID not specified', async () => {
67+
const auth = await testAuth();
68+
const userCred = new UserCredentialImpl({
69+
user: testUser(auth, 'uid'),
70+
providerId: ProviderId.GOOGLE,
71+
_tokenResponse: {
72+
...TEST_ID_TOKEN_RESPONSE,
73+
oauthAccessToken: 'access-token',
74+
oauthIdToken: 'id-token'
75+
},
76+
operationType: OperationType.SIGN_IN
77+
});
78+
expect(OAuthProvider.credentialFromResult(userCred)).to.be.null;
79+
});
80+
81+
it('credentialFromError creates the cred from a tagged error', () => {
82+
const error = _createError(AuthErrorCode.NEED_CONFIRMATION, {
83+
appName: 'foo'
84+
});
85+
(error.customData! as TaggedWithTokenResponse)._tokenResponse = {
86+
...TEST_ID_TOKEN_RESPONSE,
87+
oauthAccessToken: 'access-token',
88+
oauthIdToken: 'id-token',
89+
providerId: ProviderId.FACEBOOK
90+
};
91+
92+
const cred = OAuthProvider.credentialFromError(error)!;
93+
expect(cred.accessToken).to.eq('access-token');
94+
expect(cred.idToken).to.eq('id-token');
95+
expect(cred.providerId).to.eq(ProviderId.FACEBOOK);
96+
expect(cred.signInMethod).to.eq(SignInMethod.FACEBOOK);
97+
});
98+
});

packages-exp/auth-exp/src/core/providers/oauth.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import { _assert } from '../util/assert';
2121
import { AuthErrorCode } from '../errors';
2222

2323
import { OAuthCredential } from '../credentials/oauth';
24+
import { UserCredential } from '../../model/user';
25+
import { FirebaseError } from '@firebase/util';
26+
import { TaggedWithTokenResponse } from '../../model/id_token';
27+
import { SignInWithIdpResponse } from '../../../internal';
2428

2529
/**
2630
* Map of OAuth Custom Parameters.
@@ -203,4 +207,71 @@ export class OAuthProvider implements externs.AuthProvider {
203207
getScopes(): string[] {
204208
return [...this.scopes];
205209
}
210+
211+
/**
212+
* Used to extract the underlying {@link OAuthCredential} from a {@link @firebase/auth-types#UserCredential}.
213+
*
214+
* @param userCredential - The user credential.
215+
*/
216+
static credentialFromResult(
217+
userCredential: externs.UserCredential
218+
): externs.OAuthCredential | null {
219+
return OAuthProvider.oauthCredentialFromTaggedObject(
220+
userCredential as UserCredential
221+
);
222+
}
223+
/**
224+
* Used to extract the underlying {@link OAuthCredential} from a {@link @firebase/auth-types#AuthError} which was
225+
* thrown during a sign-in, link, or reauthenticate operation.
226+
*
227+
* @param userCredential - The user credential.
228+
*/
229+
static credentialFromError(
230+
error: FirebaseError
231+
): externs.OAuthCredential | null {
232+
return OAuthProvider.oauthCredentialFromTaggedObject(
233+
(error.customData || {}) as TaggedWithTokenResponse
234+
);
235+
}
236+
237+
// This needs to have a different name so it doesn't conflict with the
238+
// subclasses
239+
private static oauthCredentialFromTaggedObject({
240+
_tokenResponse: tokenResponse
241+
}: TaggedWithTokenResponse): externs.OAuthCredential | null {
242+
if (!tokenResponse) {
243+
return null;
244+
}
245+
246+
const {
247+
oauthIdToken,
248+
oauthAccessToken,
249+
oauthTokenSecret,
250+
pendingToken,
251+
nonce,
252+
providerId
253+
} = tokenResponse as SignInWithIdpResponse;
254+
if (
255+
!oauthAccessToken &&
256+
!oauthTokenSecret &&
257+
!oauthIdToken &&
258+
!pendingToken
259+
) {
260+
return null;
261+
}
262+
263+
if (!providerId) {
264+
return null;
265+
}
266+
267+
try {
268+
return new OAuthProvider(providerId).credential({
269+
idToken: oauthIdToken,
270+
accessToken: oauthAccessToken,
271+
rawNonce: nonce
272+
});
273+
} catch (e) {
274+
return null;
275+
}
276+
}
206277
}

packages-exp/auth-types-exp/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ export interface Auth {
215215
*
216216
* @param persistence - The {@link Persistence} to use.
217217
*/
218-
setPersistence(persistence: Persistence): void;
218+
setPersistence(persistence: Persistence): Promise<void>;
219219
/**
220220
* The Auth instance's language code.
221221
*

0 commit comments

Comments
 (0)