From ff14e14bfea0ccc2b6c1b4e0719c145353de62c7 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Wed, 22 Apr 2020 09:07:02 -0700 Subject: [PATCH 1/9] Add API method --- .../auth-exp/src/api/authentication/token.ts | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 packages-exp/auth-exp/src/api/authentication/token.ts diff --git a/packages-exp/auth-exp/src/api/authentication/token.ts b/packages-exp/auth-exp/src/api/authentication/token.ts new file mode 100644 index 00000000000..6488ff3188c --- /dev/null +++ b/packages-exp/auth-exp/src/api/authentication/token.ts @@ -0,0 +1,51 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { querystring } from '@firebase/util'; + +import { performFetchWithErrorHandling } from '../'; +import { Auth } from '../../model/auth'; + +const ENDPOINT = 'https://securetoken.googleapis.com/v1/token'; +const GRANT_TYPE = 'refresh_token'; + +export interface RequestStsTokenResponse { + access_token?: string; + expires_in?: string; + token_type?: string; + refresh_token?: string; + id_token?: string; + user_id?: string; + project_id?: string; +} + +export async function requestStsToken(auth: Auth, refreshToken: string): Promise { + return performFetchWithErrorHandling(auth, {}, () => { + const body = querystring({ + 'grant_type': GRANT_TYPE, + 'refresh_token': refreshToken, + }).slice(1); + + return fetch(`${ENDPOINT}?key=${auth.config.apiKey}`, { + method: 'POST', + headers: { + 'X-Client-Version': auth.config.sdkClientVersion, + }, + body, + }); + }); +} \ No newline at end of file From 7b0c2dda8093434153b87ca1617a78c7fb145d3c Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Wed, 22 Apr 2020 09:07:20 -0700 Subject: [PATCH 2/9] API Method --- packages-exp/auth-exp/src/api/index.ts | 56 +++++++++++-------- .../auth-exp/src/core/user/token_manager.ts | 38 +++++++++++-- 2 files changed, 65 insertions(+), 29 deletions(-) diff --git a/packages-exp/auth-exp/src/api/index.ts b/packages-exp/auth-exp/src/api/index.ts index 3882c0d6b04..16fe22cf8ab 100644 --- a/packages-exp/auth-exp/src/api/index.ts +++ b/packages-exp/auth-exp/src/api/index.ts @@ -16,16 +16,12 @@ */ import { FirebaseError, querystring } from '@firebase/util'; -import { AuthErrorCode, AUTH_ERROR_FACTORY } from '../core/errors'; + +import { AUTH_ERROR_FACTORY, AuthErrorCode } from '../core/errors'; +import { Delay } from '../core/util/delay'; import { Auth } from '../model/auth'; import { IdTokenResponse } from '../model/id_token'; -import { - JsonError, - ServerError, - ServerErrorMap, - SERVER_ERROR_MAP -} from './errors'; -import { Delay } from '../core/util/delay'; +import { JsonError, SERVER_ERROR_MAP, ServerError, ServerErrorMap } from './errors'; export enum HttpMethod { POST = 'POST', @@ -61,10 +57,9 @@ export async function _performApiRequest( method: HttpMethod, path: Endpoint, request?: T, - customErrorMap: Partial> = {} + customErrorMap: Partial> = {}, ): Promise { - const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap }; - try { + return performFetchWithErrorHandling(auth, customErrorMap, () => { let body = {}; let params = {}; if (request) { @@ -82,8 +77,7 @@ export async function _performApiRequest( ...params }).slice(1); - const response: Response = await Promise.race>([ - fetch( + return fetch( `${auth.config.apiScheme}://${auth.config.apiHost}${path}?${query}`, { method, @@ -94,16 +88,20 @@ export async function _performApiRequest( referrerPolicy: 'no-referrer', ...body } - ), - new Promise((_, reject) => - setTimeout(() => { - return reject( - AUTH_ERROR_FACTORY.create(AuthErrorCode.TIMEOUT, { - appName: auth.name - }) - ); - }, DEFAULT_API_TIMEOUT_MS.get()) - ) + ); + }); +} + +export async function performFetchWithErrorHandling( + auth: Auth, + customErrorMap: Partial>, + fetchFn: () => Promise, +): Promise { + const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap }; + try { + const response: Response = await Promise.race>([ + fetchFn(), + makeNetworkTimeout(auth.name), ]); if (response.ok) { return response.json(); @@ -154,3 +152,15 @@ export async function _performSignInRequest( return serverResponse; } + +function makeNetworkTimeout(appName: string): Promise { + return new Promise((_, reject) => + setTimeout(() => { + return reject( + AUTH_ERROR_FACTORY.create(AuthErrorCode.TIMEOUT, { + appName, + }) + ); + }, DEFAULT_API_TIMEOUT_MS.get()) +) +} diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index ade342b8d4c..be3ecebd339 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -15,7 +15,10 @@ * limitations under the License. */ +import { requestStsToken } from '../../api/authentication/token'; +import { Auth } from '../../model/auth'; import { IdTokenResponse } from '../../model/id_token'; +import { AUTH_ERROR_FACTORY, AuthErrorCode } from '../errors'; import { PersistedBlob } from '../persistence'; import { assert } from '../util/assert'; @@ -52,15 +55,23 @@ export class StsTokenManager { this.expirationTime = Date.now() + Number(expiresInSec) * 1000; } - async getToken(forceRefresh = false): Promise { + async getToken(auth: Auth, forceRefresh = false): Promise { if (!forceRefresh && this.accessToken && !this.isExpired) { - return { - accessToken: this.accessToken, - refreshToken: this.refreshToken - }; + return this.tokens; } - throw new Error('StsTokenManager: token refresh not implemented'); + if (this.accessToken && !this.refreshToken) { + throw AUTH_ERROR_FACTORY.create(AuthErrorCode.TOKEN_EXPIRED, { + appName: auth.name, + }); + } + + if (!this.refreshToken) { + return null; + } + + await this.refresh(auth, this.refreshToken); + return this.tokens; } toPlainObject(): object { @@ -71,6 +82,21 @@ export class StsTokenManager { }; } + private get tokens(): Tokens { + return { + accessToken: this.accessToken!, + refreshToken: this.refreshToken, + }; + } + + private async refresh(auth: Auth, refreshToken: string) { + const {access_token, refresh_token, expires_in} = await requestStsToken(auth, refreshToken); + + this.accessToken = access_token || null; + this.refreshToken = refresh_token || null; + this.expirationTime = expires_in ? Date.now() + Number(expires_in) * 1000 : null; + } + static fromPlainObject( appName: string, object: PersistedBlob From fb35ff7e0c5e6db54b2bd1268a8faeaf9b4c8477 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Wed, 22 Apr 2020 11:15:38 -0700 Subject: [PATCH 3/9] Token management into user_impl --- .../auth-exp/src/core/user/token_manager.ts | 35 ++++++++++--------- .../auth-exp/src/core/user/user_impl.ts | 14 +++++--- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index be3ecebd339..5a7db9e66bb 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -31,6 +31,7 @@ export const TOKEN_REFRESH_BUFFER_MS = 30_000; export interface Tokens { accessToken: string; refreshToken: string | null; + wasRefreshed: boolean; } export class StsTokenManager { @@ -50,14 +51,16 @@ export class StsTokenManager { refreshToken, expiresIn: expiresInSec }: IdTokenResponse): void { - this.refreshToken = refreshToken; - this.accessToken = idToken; - this.expirationTime = Date.now() + Number(expiresInSec) * 1000; + this.updateTokensAndExpiration(idToken, refreshToken, expiresInSec); } async getToken(auth: Auth, forceRefresh = false): Promise { if (!forceRefresh && this.accessToken && !this.isExpired) { - return this.tokens; + return { + accessToken: this.accessToken, + refreshToken: this.refreshToken, + wasRefreshed: false, + }; } if (this.accessToken && !this.refreshToken) { @@ -71,30 +74,30 @@ export class StsTokenManager { } await this.refresh(auth, this.refreshToken); - return this.tokens; - } - - toPlainObject(): object { return { + accessToken: this.accessToken!, refreshToken: this.refreshToken, - accessToken: this.accessToken, - expirationTime: this.expirationTime + wasRefreshed: true, }; } - private get tokens(): Tokens { + toPlainObject(): object { return { - accessToken: this.accessToken!, refreshToken: this.refreshToken, + accessToken: this.accessToken, + expirationTime: this.expirationTime }; } private async refresh(auth: Auth, refreshToken: string) { const {access_token, refresh_token, expires_in} = await requestStsToken(auth, refreshToken); - - this.accessToken = access_token || null; - this.refreshToken = refresh_token || null; - this.expirationTime = expires_in ? Date.now() + Number(expires_in) * 1000 : null; + this.updateTokensAndExpiration(access_token, refresh_token, expires_in); + } + + private updateTokensAndExpiration(accessToken: string|undefined, refreshToken: string|undefined, expiresInSec: string|undefined) { + this.refreshToken = refreshToken || null; + this.accessToken = accessToken || null; + this.expirationTime = expiresInSec ? Date.now() + Number(expiresInSec) * 1000 : null; } static fromPlainObject( diff --git a/packages-exp/auth-exp/src/core/user/user_impl.ts b/packages-exp/auth-exp/src/core/user/user_impl.ts index beec2877d35..c4f3867f17b 100644 --- a/packages-exp/auth-exp/src/core/user/user_impl.ts +++ b/packages-exp/auth-exp/src/core/user/user_impl.ts @@ -75,12 +75,18 @@ export class UserImpl implements User { } async getIdToken(forceRefresh?: boolean): Promise { - const { refreshToken, accessToken } = await this.stsTokenManager.getToken( - forceRefresh - ); + const tokens = await this.stsTokenManager.getToken(this.auth, forceRefresh); + assert(tokens, this.auth.name); + + // TODO: remove ! after #2934 is merged -- + const { refreshToken, accessToken, /* wasRefreshed */ } = tokens!; this.refreshToken = refreshToken || ''; - // TODO: notify listeners at this point + // TODO: Uncomment after #2961 is merged + // if (wasRefreshed && this.auth.currentUser === this) { + // this.auth._notifyListeners(); + // } + return accessToken; } From 82bb599702ee181cb2f3f30ee4eca6c2e8d8dd25 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Thu, 23 Apr 2020 11:43:16 -0700 Subject: [PATCH 4/9] Token refresh endpoint + stsTokenManager implementation --- .../src/api/authentication/token.test.ts | 85 +++++++++++++++ .../auth-exp/src/api/authentication/token.ts | 30 +++-- .../src/core/user/token_manager.test.ts | 103 +++++++++++++----- .../auth-exp/src/core/user/token_manager.ts | 8 +- .../auth-exp/src/core/user/user_impl.test.ts | 8 +- packages-exp/auth-exp/test/mock_fetch.ts | 7 +- 6 files changed, 192 insertions(+), 49 deletions(-) create mode 100644 packages-exp/auth-exp/src/api/authentication/token.test.ts diff --git a/packages-exp/auth-exp/src/api/authentication/token.test.ts b/packages-exp/auth-exp/src/api/authentication/token.test.ts new file mode 100644 index 00000000000..29a5c7d584a --- /dev/null +++ b/packages-exp/auth-exp/src/api/authentication/token.test.ts @@ -0,0 +1,85 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { expect, use } from 'chai'; +import * as chaiAsPromised from 'chai-as-promised'; + +import { FirebaseError, querystringDecode } from '@firebase/util'; + +import { mockAuth } from '../../../test/mock_auth'; +import * as fetch from '../../../test/mock_fetch'; +import { ServerError } from '../errors'; +import { _ENDPOINT, requestStsToken } from './token'; + +use(chaiAsPromised); + +describe('requestStsToken', () => { + const endpoint = `${_ENDPOINT}?key=${mockAuth.config.apiKey}`; + beforeEach(fetch.setUp); + afterEach(fetch.tearDown); + + it('should POST to the correct endpoint', async () => { + const mock = fetch.mock(endpoint, { + 'access_token': 'new-access-token', + 'expires_in': '3600', + 'refresh_token': 'new-refresh-token', + }); + + const response = await requestStsToken(mockAuth, 'old-refresh-token'); + expect(response.accessToken).to.eq('new-access-token'); + expect(response.expiresIn).to.eq('3600'); + expect(response.refreshToken).to.eq('new-refresh-token'); + const request = querystringDecode(`?${mock.calls[0].request}`); + expect(request).to.eql({ + 'grant_type': 'refresh_token', + 'refresh_token': 'old-refresh-token', + }); + expect(mock.calls[0].method).to.eq('POST'); + expect(mock.calls[0].headers).to.eql({ + 'Content-Type': 'application/x-www-form-urlencoded', + 'X-Client-Version': 'testSDK/0.0.0' + }); + }); + + it('should handle errors', async () => { + const mock = fetch.mock( + endpoint, + { + error: { + code: 400, + message: ServerError.TOKEN_EXPIRED, + errors: [ + { + message: ServerError.TOKEN_EXPIRED + } + ] + } + }, + 400 + ); + + await expect(requestStsToken(mockAuth, 'old-token')).to.be.rejectedWith( + FirebaseError, + 'Firebase: The user\'s credential is no longer valid. The user must sign in again. (auth/user-token-expired)' + ); + const request = querystringDecode(`?${mock.calls[0].request}`); + expect(request).to.eql({ + 'grant_type': 'refresh_token', + 'refresh_token': 'old-token', + }); + }); +}); diff --git a/packages-exp/auth-exp/src/api/authentication/token.ts b/packages-exp/auth-exp/src/api/authentication/token.ts index 6488ff3188c..4e68afdac59 100644 --- a/packages-exp/auth-exp/src/api/authentication/token.ts +++ b/packages-exp/auth-exp/src/api/authentication/token.ts @@ -20,32 +20,42 @@ import { querystring } from '@firebase/util'; import { performFetchWithErrorHandling } from '../'; import { Auth } from '../../model/auth'; -const ENDPOINT = 'https://securetoken.googleapis.com/v1/token'; +export const _ENDPOINT = 'https://securetoken.googleapis.com/v1/token'; const GRANT_TYPE = 'refresh_token'; +enum ServerField { + ACCESS_TOKEN = 'access_token', + EXPIRES_IN = 'expires_in', + REFRESH_TOKEN = 'refresh_token', +} + export interface RequestStsTokenResponse { - access_token?: string; - expires_in?: string; - token_type?: string; - refresh_token?: string; - id_token?: string; - user_id?: string; - project_id?: string; + accessToken?: string; + expiresIn?: string; + refreshToken?: string; } export async function requestStsToken(auth: Auth, refreshToken: string): Promise { - return performFetchWithErrorHandling(auth, {}, () => { + const response = await performFetchWithErrorHandling<{[key: string]: string}>(auth, {}, () => { const body = querystring({ 'grant_type': GRANT_TYPE, 'refresh_token': refreshToken, }).slice(1); - return fetch(`${ENDPOINT}?key=${auth.config.apiKey}`, { + return fetch(`${_ENDPOINT}?key=${auth.config.apiKey}`, { method: 'POST', headers: { 'X-Client-Version': auth.config.sdkClientVersion, + 'Content-Type': 'application/x-www-form-urlencoded', }, body, }); }); + + // The response comes back in snake_case. Convert to camel: + return { + accessToken: response[ServerField.ACCESS_TOKEN], + expiresIn: response[ServerField.EXPIRES_IN], + refreshToken: response[ServerField.REFRESH_TOKEN], + }; } \ No newline at end of file diff --git a/packages-exp/auth-exp/src/core/user/token_manager.test.ts b/packages-exp/auth-exp/src/core/user/token_manager.test.ts index 6dd7b6b430c..cd45160178a 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.test.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.test.ts @@ -17,15 +17,18 @@ import { expect, use } from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; -import { createSandbox } from 'sinon'; +import * as sinon from 'sinon'; + +import { FirebaseError } from '@firebase/util'; + +import { mockAuth } from '../../../test/mock_auth'; +import * as fetch from '../../../test/mock_fetch'; +import { _ENDPOINT } from '../../api/authentication/token'; import { IdTokenResponse } from '../../model/id_token'; import { StsTokenManager, TOKEN_REFRESH_BUFFER_MS } from './token_manager'; -import { FirebaseError } from '@firebase/util'; use(chaiAsPromised); -const sandbox = createSandbox(); - describe('core/user/token_manager', () => { let stsTokenManager: StsTokenManager; let now: number; @@ -33,10 +36,12 @@ describe('core/user/token_manager', () => { beforeEach(() => { stsTokenManager = new StsTokenManager(); now = Date.now(); - sandbox.stub(Date, 'now').returns(now); + sinon.stub(Date, 'now').returns(now); }); - afterEach(() => sandbox.restore()); + beforeEach(fetch.setUp); + afterEach(fetch.tearDown); + afterEach(() => sinon.restore()); describe('#isExpired', () => { it('is true if past expiration time', () => { @@ -70,32 +75,71 @@ describe('core/user/token_manager', () => { }); describe('#getToken', () => { - it('throws if forceRefresh is true', async () => { - Object.assign(stsTokenManager, { - accessToken: 'token', - expirationTime: now + 100_000 + context('with endpoint setup', () => { + let mock: fetch.Route; + beforeEach(() => { + const endpoint = `${_ENDPOINT}?key=${mockAuth.config.apiKey}`; + mock = fetch.mock(endpoint, { + 'access_token': 'new-access-token', + 'refresh_token': 'new-refresh-token', + 'expires_in': '3600', + }); + }); + + it('refreshes the token if forceRefresh is true', async () => { + Object.assign(stsTokenManager, { + accessToken: 'old-access-token', + refreshToken: 'old-refresh-token', + expirationTime: now + 100_000 + }); + + const tokens = await stsTokenManager.getToken(mockAuth, true); + expect(mock.calls[0].request).to.contain('old-refresh-token'); + expect(stsTokenManager.accessToken).to.eq('new-access-token'); + expect(stsTokenManager.refreshToken).to.eq('new-refresh-token'); + expect(stsTokenManager.expirationTime).to.eq(now + 3_600_000); + + expect(tokens).to.eql({ + accessToken: 'new-access-token', + refreshToken: 'new-refresh-token', + wasRefreshed: true, + }); + }); + + it('refreshes the token if token is expired', async () => { + Object.assign(stsTokenManager, { + accessToken: 'old-access-token', + refreshToken: 'old-refresh-token', + expirationTime: now - 1 + }); + + const tokens = await stsTokenManager.getToken(mockAuth, false); + expect(mock.calls[0].request).to.contain('old-refresh-token'); + expect(stsTokenManager.accessToken).to.eq('new-access-token'); + expect(stsTokenManager.refreshToken).to.eq('new-refresh-token'); + expect(stsTokenManager.expirationTime).to.eq(now + 3_600_000); + + expect(tokens).to.eql({ + accessToken: 'new-access-token', + refreshToken: 'new-refresh-token', + wasRefreshed: true, + }); }); - await expect(stsTokenManager.getToken(true)).to.be.rejectedWith( - Error, - 'StsTokenManager: token refresh not implemented' - ); }); - it('throws if token is expired', async () => { + it('returns null if the refresh token is missing', async () => { + expect(await stsTokenManager.getToken(mockAuth)).to.be.null; + }); + + it('throws an error if expired but refresh token is missing', async () => { Object.assign(stsTokenManager, { - accessToken: 'token', + accessToken: 'old-access-token', expirationTime: now - 1 }); - await expect(stsTokenManager.getToken()).to.be.rejectedWith( - Error, - 'StsTokenManager: token refresh not implemented' - ); - }); - it('throws if access token is missing', async () => { - await expect(stsTokenManager.getToken()).to.be.rejectedWith( - Error, - 'StsTokenManager: token refresh not implemented' + await expect(stsTokenManager.getToken(mockAuth)).to.be.rejectedWith( + FirebaseError, + 'Firebase: The user\'s credential is no longer valid. The user must sign in again. (auth/user-token-expired)' ); }); @@ -106,9 +150,12 @@ describe('core/user/token_manager', () => { expirationTime: now + 100_000 }); - const tokens = await stsTokenManager.getToken(); - expect(tokens.accessToken).to.eq('token'); - expect(tokens.refreshToken).to.eq('refresh'); + const tokens = (await stsTokenManager.getToken(mockAuth))!; + expect(tokens).to.eql({ + accessToken: 'token', + refreshToken: 'refresh', + wasRefreshed: false, + }); }); }); diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index 5a7db9e66bb..2ec1dc07f0c 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -89,12 +89,12 @@ export class StsTokenManager { }; } - private async refresh(auth: Auth, refreshToken: string) { - const {access_token, refresh_token, expires_in} = await requestStsToken(auth, refreshToken); - this.updateTokensAndExpiration(access_token, refresh_token, expires_in); + private async refresh(auth: Auth, oldToken: string): Promise { + const {accessToken, refreshToken, expiresIn} = await requestStsToken(auth, oldToken); + this.updateTokensAndExpiration(accessToken, refreshToken, expiresIn); } - private updateTokensAndExpiration(accessToken: string|undefined, refreshToken: string|undefined, expiresInSec: string|undefined) { + private updateTokensAndExpiration(accessToken: string|undefined, refreshToken: string|undefined, expiresInSec: string|undefined): void { this.refreshToken = refreshToken || null; this.accessToken = accessToken || null; this.expirationTime = expiresInSec ? Date.now() + Number(expiresInSec) * 1000 : null; diff --git a/packages-exp/auth-exp/src/core/user/user_impl.test.ts b/packages-exp/auth-exp/src/core/user/user_impl.test.ts index 4fb7cb140e1..f3226ad7c06 100644 --- a/packages-exp/auth-exp/src/core/user/user_impl.test.ts +++ b/packages-exp/auth-exp/src/core/user/user_impl.test.ts @@ -18,6 +18,9 @@ import { FirebaseError } from '@firebase/util'; import { expect, use } from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; + +import { FirebaseError } from '@firebase/util'; + import { mockAuth } from '../../../test/mock_auth'; import { IdTokenResponse } from '../../model/id_token'; import { StsTokenManager } from './token_manager'; @@ -79,11 +82,6 @@ describe('core/user/user_impl', () => { expect(token).to.eq('id-token-string'); expect(user.refreshToken).to.eq('refresh-token-string'); }); - - it('throws if refresh is required', async () => { - const user = new UserImpl({ uid: 'uid', auth, stsTokenManager }); - await expect(user.getIdToken()).to.be.rejectedWith(Error); - }); }); describe('#getIdTokenResult', () => { diff --git a/packages-exp/auth-exp/test/mock_fetch.ts b/packages-exp/auth-exp/test/mock_fetch.ts index 2d1cafb71ab..8d7e3852d7f 100644 --- a/packages-exp/auth-exp/test/mock_fetch.ts +++ b/packages-exp/auth-exp/test/mock_fetch.ts @@ -18,7 +18,7 @@ import { SinonStub, stub } from 'sinon'; export interface Call { - request?: object; + request?: object|string; method?: string; headers?: HeadersInit; } @@ -45,8 +45,11 @@ const fakeFetch: typeof fetch = (input: RequestInfo, request?: RequestInit) => { // Bang-assertion is fine since we check for routes.has() above const { response, status, calls } = routes.get(input)!; + const requestBody = request?.body && (request?.headers as any)?.['Content-Type'] === 'application/json' ? + JSON.parse(request.body as string) : request?.body; + calls.push({ - request: request?.body ? JSON.parse(request.body as string) : undefined, + request: requestBody, method: request?.method, headers: request?.headers }); From ffedcb2059f57d8945a10f936fc2de3e56a34942 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Thu, 23 Apr 2020 11:45:32 -0700 Subject: [PATCH 5/9] [AUTOMATED]: Prettier Code Styling --- .../src/api/authentication/token.test.ts | 8 ++-- .../auth-exp/src/api/authentication/token.ts | 21 +++++---- packages-exp/auth-exp/src/api/index.ts | 47 +++++++++---------- .../src/core/user/token_manager.test.ts | 10 ++-- .../auth-exp/src/core/user/token_manager.ts | 23 ++++++--- .../auth-exp/src/core/user/user_impl.ts | 2 +- packages-exp/auth-exp/test/mock_fetch.ts | 9 ++-- 7 files changed, 68 insertions(+), 52 deletions(-) diff --git a/packages-exp/auth-exp/src/api/authentication/token.test.ts b/packages-exp/auth-exp/src/api/authentication/token.test.ts index 29a5c7d584a..95e246fbee8 100644 --- a/packages-exp/auth-exp/src/api/authentication/token.test.ts +++ b/packages-exp/auth-exp/src/api/authentication/token.test.ts @@ -36,7 +36,7 @@ describe('requestStsToken', () => { const mock = fetch.mock(endpoint, { 'access_token': 'new-access-token', 'expires_in': '3600', - 'refresh_token': 'new-refresh-token', + 'refresh_token': 'new-refresh-token' }); const response = await requestStsToken(mockAuth, 'old-refresh-token'); @@ -46,7 +46,7 @@ describe('requestStsToken', () => { const request = querystringDecode(`?${mock.calls[0].request}`); expect(request).to.eql({ 'grant_type': 'refresh_token', - 'refresh_token': 'old-refresh-token', + 'refresh_token': 'old-refresh-token' }); expect(mock.calls[0].method).to.eq('POST'); expect(mock.calls[0].headers).to.eql({ @@ -74,12 +74,12 @@ describe('requestStsToken', () => { await expect(requestStsToken(mockAuth, 'old-token')).to.be.rejectedWith( FirebaseError, - 'Firebase: The user\'s credential is no longer valid. The user must sign in again. (auth/user-token-expired)' + "Firebase: The user's credential is no longer valid. The user must sign in again. (auth/user-token-expired)" ); const request = querystringDecode(`?${mock.calls[0].request}`); expect(request).to.eql({ 'grant_type': 'refresh_token', - 'refresh_token': 'old-token', + 'refresh_token': 'old-token' }); }); }); diff --git a/packages-exp/auth-exp/src/api/authentication/token.ts b/packages-exp/auth-exp/src/api/authentication/token.ts index 4e68afdac59..b92a4898739 100644 --- a/packages-exp/auth-exp/src/api/authentication/token.ts +++ b/packages-exp/auth-exp/src/api/authentication/token.ts @@ -26,7 +26,7 @@ const GRANT_TYPE = 'refresh_token'; enum ServerField { ACCESS_TOKEN = 'access_token', EXPIRES_IN = 'expires_in', - REFRESH_TOKEN = 'refresh_token', + REFRESH_TOKEN = 'refresh_token' } export interface RequestStsTokenResponse { @@ -35,20 +35,25 @@ export interface RequestStsTokenResponse { refreshToken?: string; } -export async function requestStsToken(auth: Auth, refreshToken: string): Promise { - const response = await performFetchWithErrorHandling<{[key: string]: string}>(auth, {}, () => { +export async function requestStsToken( + auth: Auth, + refreshToken: string +): Promise { + const response = await performFetchWithErrorHandling<{ + [key: string]: string; + }>(auth, {}, () => { const body = querystring({ 'grant_type': GRANT_TYPE, - 'refresh_token': refreshToken, + 'refresh_token': refreshToken }).slice(1); return fetch(`${_ENDPOINT}?key=${auth.config.apiKey}`, { method: 'POST', headers: { 'X-Client-Version': auth.config.sdkClientVersion, - 'Content-Type': 'application/x-www-form-urlencoded', + 'Content-Type': 'application/x-www-form-urlencoded' }, - body, + body }); }); @@ -56,6 +61,6 @@ export async function requestStsToken(auth: Auth, refreshToken: string): Promise return { accessToken: response[ServerField.ACCESS_TOKEN], expiresIn: response[ServerField.EXPIRES_IN], - refreshToken: response[ServerField.REFRESH_TOKEN], + refreshToken: response[ServerField.REFRESH_TOKEN] }; -} \ No newline at end of file +} diff --git a/packages-exp/auth-exp/src/api/index.ts b/packages-exp/auth-exp/src/api/index.ts index 16fe22cf8ab..3e987d33ecf 100644 --- a/packages-exp/auth-exp/src/api/index.ts +++ b/packages-exp/auth-exp/src/api/index.ts @@ -57,7 +57,7 @@ export async function _performApiRequest( method: HttpMethod, path: Endpoint, request?: T, - customErrorMap: Partial> = {}, + customErrorMap: Partial> = {} ): Promise { return performFetchWithErrorHandling(auth, customErrorMap, () => { let body = {}; @@ -77,31 +77,31 @@ export async function _performApiRequest( ...params }).slice(1); - return fetch( - `${auth.config.apiScheme}://${auth.config.apiHost}${path}?${query}`, - { - method, - headers: { - 'Content-Type': 'application/json', - 'X-Client-Version': auth.config.sdkClientVersion - }, - referrerPolicy: 'no-referrer', - ...body - } - ); - }); + return fetch( + `${auth.config.apiScheme}://${auth.config.apiHost}${path}?${query}`, + { + method, + headers: { + 'Content-Type': 'application/json', + 'X-Client-Version': auth.config.sdkClientVersion + }, + referrerPolicy: 'no-referrer', + ...body + } + ); + }); } export async function performFetchWithErrorHandling( auth: Auth, customErrorMap: Partial>, - fetchFn: () => Promise, + fetchFn: () => Promise ): Promise { const errorMap = { ...SERVER_ERROR_MAP, ...customErrorMap }; try { const response: Response = await Promise.race>([ fetchFn(), - makeNetworkTimeout(auth.name), + makeNetworkTimeout(auth.name) ]); if (response.ok) { return response.json(); @@ -155,12 +155,11 @@ export async function _performSignInRequest( function makeNetworkTimeout(appName: string): Promise { return new Promise((_, reject) => - setTimeout(() => { - return reject( - AUTH_ERROR_FACTORY.create(AuthErrorCode.TIMEOUT, { - appName, - }) - ); - }, DEFAULT_API_TIMEOUT_MS.get()) -) + setTimeout(() => { + return reject( + AUTH_ERROR_FACTORY.create(AuthErrorCode.TIMEOUT, { + appName, + }) + ); + }, DEFAULT_API_TIMEOUT_MS.get())); } diff --git a/packages-exp/auth-exp/src/core/user/token_manager.test.ts b/packages-exp/auth-exp/src/core/user/token_manager.test.ts index cd45160178a..01d85dcc571 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.test.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.test.ts @@ -82,7 +82,7 @@ describe('core/user/token_manager', () => { mock = fetch.mock(endpoint, { 'access_token': 'new-access-token', 'refresh_token': 'new-refresh-token', - 'expires_in': '3600', + 'expires_in': '3600' }); }); @@ -102,7 +102,7 @@ describe('core/user/token_manager', () => { expect(tokens).to.eql({ accessToken: 'new-access-token', refreshToken: 'new-refresh-token', - wasRefreshed: true, + wasRefreshed: true }); }); @@ -122,7 +122,7 @@ describe('core/user/token_manager', () => { expect(tokens).to.eql({ accessToken: 'new-access-token', refreshToken: 'new-refresh-token', - wasRefreshed: true, + wasRefreshed: true }); }); }); @@ -139,7 +139,7 @@ describe('core/user/token_manager', () => { await expect(stsTokenManager.getToken(mockAuth)).to.be.rejectedWith( FirebaseError, - 'Firebase: The user\'s credential is no longer valid. The user must sign in again. (auth/user-token-expired)' + "Firebase: The user's credential is no longer valid. The user must sign in again. (auth/user-token-expired)" ); }); @@ -154,7 +154,7 @@ describe('core/user/token_manager', () => { expect(tokens).to.eql({ accessToken: 'token', refreshToken: 'refresh', - wasRefreshed: false, + wasRefreshed: false }); }); }); diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index 2ec1dc07f0c..d392696f91a 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -54,18 +54,18 @@ export class StsTokenManager { this.updateTokensAndExpiration(idToken, refreshToken, expiresInSec); } - async getToken(auth: Auth, forceRefresh = false): Promise { + async getToken(auth: Auth, forceRefresh = false): Promise { if (!forceRefresh && this.accessToken && !this.isExpired) { return { accessToken: this.accessToken, refreshToken: this.refreshToken, - wasRefreshed: false, + wasRefreshed: false }; } if (this.accessToken && !this.refreshToken) { throw AUTH_ERROR_FACTORY.create(AuthErrorCode.TOKEN_EXPIRED, { - appName: auth.name, + appName: auth.name }); } @@ -77,7 +77,7 @@ export class StsTokenManager { return { accessToken: this.accessToken!, refreshToken: this.refreshToken, - wasRefreshed: true, + wasRefreshed: true }; } @@ -90,14 +90,23 @@ export class StsTokenManager { } private async refresh(auth: Auth, oldToken: string): Promise { - const {accessToken, refreshToken, expiresIn} = await requestStsToken(auth, oldToken); + const { accessToken, refreshToken, expiresIn } = await requestStsToken( + auth, + oldToken + ); this.updateTokensAndExpiration(accessToken, refreshToken, expiresIn); } - private updateTokensAndExpiration(accessToken: string|undefined, refreshToken: string|undefined, expiresInSec: string|undefined): void { + private updateTokensAndExpiration( + accessToken: string | undefined, + refreshToken: string | undefined, + expiresInSec: string | undefined + ): void { this.refreshToken = refreshToken || null; this.accessToken = accessToken || null; - this.expirationTime = expiresInSec ? Date.now() + Number(expiresInSec) * 1000 : null; + this.expirationTime = expiresInSec + ? Date.now() + Number(expiresInSec) * 1000 + : null; } static fromPlainObject( diff --git a/packages-exp/auth-exp/src/core/user/user_impl.ts b/packages-exp/auth-exp/src/core/user/user_impl.ts index c4f3867f17b..843713b2861 100644 --- a/packages-exp/auth-exp/src/core/user/user_impl.ts +++ b/packages-exp/auth-exp/src/core/user/user_impl.ts @@ -79,7 +79,7 @@ export class UserImpl implements User { assert(tokens, this.auth.name); // TODO: remove ! after #2934 is merged -- - const { refreshToken, accessToken, /* wasRefreshed */ } = tokens!; + const { refreshToken, accessToken /* wasRefreshed */ } = tokens!; this.refreshToken = refreshToken || ''; // TODO: Uncomment after #2961 is merged diff --git a/packages-exp/auth-exp/test/mock_fetch.ts b/packages-exp/auth-exp/test/mock_fetch.ts index 8d7e3852d7f..a4d35ebf01d 100644 --- a/packages-exp/auth-exp/test/mock_fetch.ts +++ b/packages-exp/auth-exp/test/mock_fetch.ts @@ -18,7 +18,7 @@ import { SinonStub, stub } from 'sinon'; export interface Call { - request?: object|string; + request?: object | string; method?: string; headers?: HeadersInit; } @@ -45,8 +45,11 @@ const fakeFetch: typeof fetch = (input: RequestInfo, request?: RequestInit) => { // Bang-assertion is fine since we check for routes.has() above const { response, status, calls } = routes.get(input)!; - const requestBody = request?.body && (request?.headers as any)?.['Content-Type'] === 'application/json' ? - JSON.parse(request.body as string) : request?.body; + const requestBody = + request?.body && + (request?.headers as any)?.['Content-Type'] === 'application/json' + ? JSON.parse(request.body as string) + : request?.body; calls.push({ request: requestBody, From 2d1ff5ab489ec30a2b22650b0a8bdb6a92229d04 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Thu, 23 Apr 2020 12:13:14 -0700 Subject: [PATCH 6/9] PR comments --- .../src/api/authentication/token.test.ts | 3 +- .../auth-exp/src/api/authentication/token.ts | 33 ++++++++++--------- .../auth-exp/src/core/auth/auth_impl.test.ts | 7 ++-- .../auth-exp/src/core/auth/auth_impl.ts | 2 ++ .../src/core/user/token_manager.test.ts | 4 ++- .../auth-exp/src/core/user/token_manager.ts | 12 +++---- packages-exp/auth-exp/src/model/auth.d.ts | 1 + packages-exp/auth-exp/test/mock_auth.ts | 2 ++ 8 files changed, 37 insertions(+), 27 deletions(-) diff --git a/packages-exp/auth-exp/src/api/authentication/token.test.ts b/packages-exp/auth-exp/src/api/authentication/token.test.ts index 95e246fbee8..87b37f78f03 100644 --- a/packages-exp/auth-exp/src/api/authentication/token.test.ts +++ b/packages-exp/auth-exp/src/api/authentication/token.test.ts @@ -28,7 +28,8 @@ import { _ENDPOINT, requestStsToken } from './token'; use(chaiAsPromised); describe('requestStsToken', () => { - const endpoint = `${_ENDPOINT}?key=${mockAuth.config.apiKey}`; + const {apiKey, tokenApiHost, apiScheme} = mockAuth.config; + const endpoint = `${apiScheme}://${tokenApiHost}/${_ENDPOINT}?key=${apiKey}`; beforeEach(fetch.setUp); afterEach(fetch.tearDown); diff --git a/packages-exp/auth-exp/src/api/authentication/token.ts b/packages-exp/auth-exp/src/api/authentication/token.ts index b92a4898739..f2c54225a69 100644 --- a/packages-exp/auth-exp/src/api/authentication/token.ts +++ b/packages-exp/auth-exp/src/api/authentication/token.ts @@ -15,18 +15,21 @@ * limitations under the License. */ +/* eslint-disable camelcase */ + import { querystring } from '@firebase/util'; -import { performFetchWithErrorHandling } from '../'; +import { HttpMethod, performFetchWithErrorHandling } from '../'; import { Auth } from '../../model/auth'; -export const _ENDPOINT = 'https://securetoken.googleapis.com/v1/token'; +export const _ENDPOINT = 'v1/token'; const GRANT_TYPE = 'refresh_token'; -enum ServerField { - ACCESS_TOKEN = 'access_token', - EXPIRES_IN = 'expires_in', - REFRESH_TOKEN = 'refresh_token' +/** The server responses with snake_case; we convert to camelCase */ +interface RequestStsTokenServerResponse { + access_token?: string; + expires_in?: string; + refresh_token?: string; } export interface RequestStsTokenResponse { @@ -39,18 +42,18 @@ export async function requestStsToken( auth: Auth, refreshToken: string ): Promise { - const response = await performFetchWithErrorHandling<{ - [key: string]: string; - }>(auth, {}, () => { + const response = await performFetchWithErrorHandling(auth, {}, () => { const body = querystring({ 'grant_type': GRANT_TYPE, 'refresh_token': refreshToken }).slice(1); + const {apiScheme, tokenApiHost, apiKey, sdkClientVersion} = auth.config; + const url = `${apiScheme}://${tokenApiHost}/${_ENDPOINT}`; - return fetch(`${_ENDPOINT}?key=${auth.config.apiKey}`, { - method: 'POST', + return fetch(`${url}?key=${apiKey}`, { + method: HttpMethod.POST, headers: { - 'X-Client-Version': auth.config.sdkClientVersion, + 'X-Client-Version': sdkClientVersion, 'Content-Type': 'application/x-www-form-urlencoded' }, body @@ -59,8 +62,8 @@ export async function requestStsToken( // The response comes back in snake_case. Convert to camel: return { - accessToken: response[ServerField.ACCESS_TOKEN], - expiresIn: response[ServerField.EXPIRES_IN], - refreshToken: response[ServerField.REFRESH_TOKEN] + accessToken: response.access_token, + expiresIn: response.expires_in, + refreshToken: response.refresh_token }; } diff --git a/packages-exp/auth-exp/src/core/auth/auth_impl.test.ts b/packages-exp/auth-exp/src/core/auth/auth_impl.test.ts index 0f57a3113db..f4c593079c0 100644 --- a/packages-exp/auth-exp/src/core/auth/auth_impl.test.ts +++ b/packages-exp/auth-exp/src/core/auth/auth_impl.test.ts @@ -29,11 +29,9 @@ import { Persistence } from '../persistence'; import { browserLocalPersistence } from '../persistence/browser'; import { inMemoryPersistence } from '../persistence/in_memory'; import { PersistenceUserManager } from '../persistence/persistence_user_manager'; -import { ClientPlatform, _getClientVersion } from '../util/version'; +import { _getClientVersion, ClientPlatform } from '../util/version'; import { - DEFAULT_API_HOST, - DEFAULT_API_SCHEME, - initializeAuth + DEFAULT_API_HOST, DEFAULT_API_SCHEME, DEFAULT_TOKEN_API_HOST, initializeAuth } from './auth_impl'; use(sinonChai); @@ -318,6 +316,7 @@ describe('core/auth/initializeAuth', () => { authDomain: FAKE_APP.options.authDomain, apiHost: DEFAULT_API_HOST, apiScheme: DEFAULT_API_SCHEME, + tokenApiHost: DEFAULT_TOKEN_API_HOST, sdkClientVersion: _getClientVersion(ClientPlatform.BROWSER) }); }); diff --git a/packages-exp/auth-exp/src/core/auth/auth_impl.ts b/packages-exp/auth-exp/src/core/auth/auth_impl.ts index 30045cbba84..db0896e1aca 100644 --- a/packages-exp/auth-exp/src/core/auth/auth_impl.ts +++ b/packages-exp/auth-exp/src/core/auth/auth_impl.ts @@ -39,6 +39,7 @@ interface AsyncAction { (): Promise; } +export const DEFAULT_TOKEN_API_HOST = 'securetoken.googleapis.com'; export const DEFAULT_API_HOST = 'identitytoolkit.googleapis.com'; export const DEFAULT_API_SCHEME = 'https'; @@ -199,6 +200,7 @@ export function initializeAuth( apiKey, authDomain, apiHost: DEFAULT_API_HOST, + tokenApiHost: DEFAULT_TOKEN_API_HOST, apiScheme: DEFAULT_API_SCHEME, sdkClientVersion: _getClientVersion(ClientPlatform.BROWSER) }; diff --git a/packages-exp/auth-exp/src/core/user/token_manager.test.ts b/packages-exp/auth-exp/src/core/user/token_manager.test.ts index 01d85dcc571..7201a6e5304 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.test.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.test.ts @@ -78,7 +78,9 @@ describe('core/user/token_manager', () => { context('with endpoint setup', () => { let mock: fetch.Route; beforeEach(() => { - const endpoint = `${_ENDPOINT}?key=${mockAuth.config.apiKey}`; + const {apiKey, tokenApiHost, apiScheme} = mockAuth.config; + const endpoint = + `${apiScheme}://${tokenApiHost}/${_ENDPOINT}?key=${apiKey}`; mock = fetch.mock(endpoint, { 'access_token': 'new-access-token', 'refresh_token': 'new-refresh-token', diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index d392696f91a..0393a630f68 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -94,16 +94,16 @@ export class StsTokenManager { auth, oldToken ); - this.updateTokensAndExpiration(accessToken, refreshToken, expiresIn); + this.updateTokensAndExpiration(accessToken || null, refreshToken || null, expiresIn || null); } private updateTokensAndExpiration( - accessToken: string | undefined, - refreshToken: string | undefined, - expiresInSec: string | undefined + accessToken: string | null, + refreshToken: string | null, + expiresInSec: string | null ): void { - this.refreshToken = refreshToken || null; - this.accessToken = accessToken || null; + this.refreshToken = refreshToken; + this.accessToken = accessToken; this.expirationTime = expiresInSec ? Date.now() + Number(expiresInSec) * 1000 : null; diff --git a/packages-exp/auth-exp/src/model/auth.d.ts b/packages-exp/auth-exp/src/model/auth.d.ts index 5b41395abb4..478380b15da 100644 --- a/packages-exp/auth-exp/src/model/auth.d.ts +++ b/packages-exp/auth-exp/src/model/auth.d.ts @@ -35,6 +35,7 @@ export interface Config { apiKey: ApiKey; apiHost: string; apiScheme: string; + tokenApiHost: string; sdkClientVersion: string; authDomain?: AuthDomain; } diff --git a/packages-exp/auth-exp/test/mock_auth.ts b/packages-exp/auth-exp/test/mock_auth.ts index d9f7f87e1b6..90b76a1b297 100644 --- a/packages-exp/auth-exp/test/mock_auth.ts +++ b/packages-exp/auth-exp/test/mock_auth.ts @@ -21,6 +21,7 @@ import { Auth } from '../src/model/auth'; import { User } from '../src/model/user'; export const TEST_HOST = 'localhost'; +export const TEST_TOKEN_HOST = 'localhost/token'; export const TEST_SCHEME = 'mock'; export const TEST_KEY = 'test-api-key'; @@ -30,6 +31,7 @@ export const mockAuth: Auth = { apiKey: TEST_KEY, apiHost: TEST_HOST, apiScheme: TEST_SCHEME, + tokenApiHost: TEST_TOKEN_HOST, sdkClientVersion: 'testSDK/0.0.0' }, _isInitialized: true, From 1b0a6d86e144d4b7c7f151e5f0082e20a8833456 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Thu, 23 Apr 2020 12:13:20 -0700 Subject: [PATCH 7/9] [AUTOMATED]: Prettier Code Styling --- packages-exp/auth-exp/src/api/authentication/token.test.ts | 2 +- packages-exp/auth-exp/src/api/authentication/token.ts | 6 ++++-- packages-exp/auth-exp/src/core/auth/auth_impl.test.ts | 5 ++++- packages-exp/auth-exp/src/core/user/token_manager.test.ts | 5 ++--- packages-exp/auth-exp/src/core/user/token_manager.ts | 6 +++++- 5 files changed, 16 insertions(+), 8 deletions(-) diff --git a/packages-exp/auth-exp/src/api/authentication/token.test.ts b/packages-exp/auth-exp/src/api/authentication/token.test.ts index 87b37f78f03..10ed61b8ca9 100644 --- a/packages-exp/auth-exp/src/api/authentication/token.test.ts +++ b/packages-exp/auth-exp/src/api/authentication/token.test.ts @@ -28,7 +28,7 @@ import { _ENDPOINT, requestStsToken } from './token'; use(chaiAsPromised); describe('requestStsToken', () => { - const {apiKey, tokenApiHost, apiScheme} = mockAuth.config; + const { apiKey, tokenApiHost, apiScheme } = mockAuth.config; const endpoint = `${apiScheme}://${tokenApiHost}/${_ENDPOINT}?key=${apiKey}`; beforeEach(fetch.setUp); afterEach(fetch.tearDown); diff --git a/packages-exp/auth-exp/src/api/authentication/token.ts b/packages-exp/auth-exp/src/api/authentication/token.ts index f2c54225a69..19dc964b519 100644 --- a/packages-exp/auth-exp/src/api/authentication/token.ts +++ b/packages-exp/auth-exp/src/api/authentication/token.ts @@ -42,12 +42,14 @@ export async function requestStsToken( auth: Auth, refreshToken: string ): Promise { - const response = await performFetchWithErrorHandling(auth, {}, () => { + const response = await performFetchWithErrorHandling< + RequestStsTokenServerResponse + >(auth, {}, () => { const body = querystring({ 'grant_type': GRANT_TYPE, 'refresh_token': refreshToken }).slice(1); - const {apiScheme, tokenApiHost, apiKey, sdkClientVersion} = auth.config; + const { apiScheme, tokenApiHost, apiKey, sdkClientVersion } = auth.config; const url = `${apiScheme}://${tokenApiHost}/${_ENDPOINT}`; return fetch(`${url}?key=${apiKey}`, { diff --git a/packages-exp/auth-exp/src/core/auth/auth_impl.test.ts b/packages-exp/auth-exp/src/core/auth/auth_impl.test.ts index f4c593079c0..f1a7e9a3d45 100644 --- a/packages-exp/auth-exp/src/core/auth/auth_impl.test.ts +++ b/packages-exp/auth-exp/src/core/auth/auth_impl.test.ts @@ -31,7 +31,10 @@ import { inMemoryPersistence } from '../persistence/in_memory'; import { PersistenceUserManager } from '../persistence/persistence_user_manager'; import { _getClientVersion, ClientPlatform } from '../util/version'; import { - DEFAULT_API_HOST, DEFAULT_API_SCHEME, DEFAULT_TOKEN_API_HOST, initializeAuth + DEFAULT_API_HOST, + DEFAULT_API_SCHEME, + DEFAULT_TOKEN_API_HOST, + initializeAuth } from './auth_impl'; use(sinonChai); diff --git a/packages-exp/auth-exp/src/core/user/token_manager.test.ts b/packages-exp/auth-exp/src/core/user/token_manager.test.ts index 7201a6e5304..e5fcaf8031c 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.test.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.test.ts @@ -78,9 +78,8 @@ describe('core/user/token_manager', () => { context('with endpoint setup', () => { let mock: fetch.Route; beforeEach(() => { - const {apiKey, tokenApiHost, apiScheme} = mockAuth.config; - const endpoint = - `${apiScheme}://${tokenApiHost}/${_ENDPOINT}?key=${apiKey}`; + const { apiKey, tokenApiHost, apiScheme } = mockAuth.config; + const endpoint = `${apiScheme}://${tokenApiHost}/${_ENDPOINT}?key=${apiKey}`; mock = fetch.mock(endpoint, { 'access_token': 'new-access-token', 'refresh_token': 'new-refresh-token', diff --git a/packages-exp/auth-exp/src/core/user/token_manager.ts b/packages-exp/auth-exp/src/core/user/token_manager.ts index 0393a630f68..ce07e417e4b 100644 --- a/packages-exp/auth-exp/src/core/user/token_manager.ts +++ b/packages-exp/auth-exp/src/core/user/token_manager.ts @@ -94,7 +94,11 @@ export class StsTokenManager { auth, oldToken ); - this.updateTokensAndExpiration(accessToken || null, refreshToken || null, expiresIn || null); + this.updateTokensAndExpiration( + accessToken || null, + refreshToken || null, + expiresIn || null + ); } private updateTokensAndExpiration( From f681e6a097631f39c558e10f0a4581803eaa2809 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Fri, 24 Apr 2020 12:41:07 -0700 Subject: [PATCH 8/9] Renaming symbols --- packages-exp/auth-exp/src/api/authentication/token.ts | 4 ++-- packages-exp/auth-exp/src/api/index.ts | 4 ++-- packages-exp/auth-exp/src/core/user/user_impl.test.ts | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages-exp/auth-exp/src/api/authentication/token.ts b/packages-exp/auth-exp/src/api/authentication/token.ts index 19dc964b519..ceb186b6d7d 100644 --- a/packages-exp/auth-exp/src/api/authentication/token.ts +++ b/packages-exp/auth-exp/src/api/authentication/token.ts @@ -19,7 +19,7 @@ import { querystring } from '@firebase/util'; -import { HttpMethod, performFetchWithErrorHandling } from '../'; +import { _performFetchWithErrorHandling, HttpMethod } from '../'; import { Auth } from '../../model/auth'; export const _ENDPOINT = 'v1/token'; @@ -42,7 +42,7 @@ export async function requestStsToken( auth: Auth, refreshToken: string ): Promise { - const response = await performFetchWithErrorHandling< + const response = await _performFetchWithErrorHandling< RequestStsTokenServerResponse >(auth, {}, () => { const body = querystring({ diff --git a/packages-exp/auth-exp/src/api/index.ts b/packages-exp/auth-exp/src/api/index.ts index 3e987d33ecf..aa51717c5f6 100644 --- a/packages-exp/auth-exp/src/api/index.ts +++ b/packages-exp/auth-exp/src/api/index.ts @@ -59,7 +59,7 @@ export async function _performApiRequest( request?: T, customErrorMap: Partial> = {} ): Promise { - return performFetchWithErrorHandling(auth, customErrorMap, () => { + return _performFetchWithErrorHandling(auth, customErrorMap, () => { let body = {}; let params = {}; if (request) { @@ -92,7 +92,7 @@ export async function _performApiRequest( }); } -export async function performFetchWithErrorHandling( +export async function _performFetchWithErrorHandling( auth: Auth, customErrorMap: Partial>, fetchFn: () => Promise diff --git a/packages-exp/auth-exp/src/core/user/user_impl.test.ts b/packages-exp/auth-exp/src/core/user/user_impl.test.ts index f3226ad7c06..ccda66ef1e4 100644 --- a/packages-exp/auth-exp/src/core/user/user_impl.test.ts +++ b/packages-exp/auth-exp/src/core/user/user_impl.test.ts @@ -15,7 +15,6 @@ * limitations under the License. */ -import { FirebaseError } from '@firebase/util'; import { expect, use } from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; From 4d4c71d71aa6e1aad5e8d73308b2b1330d5ef545 Mon Sep 17 00:00:00 2001 From: Sam Olsen Date: Fri, 24 Apr 2020 12:41:15 -0700 Subject: [PATCH 9/9] [AUTOMATED]: Prettier Code Styling --- packages-exp/auth-exp/src/api/index.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages-exp/auth-exp/src/api/index.ts b/packages-exp/auth-exp/src/api/index.ts index aa51717c5f6..952bfcc41ff 100644 --- a/packages-exp/auth-exp/src/api/index.ts +++ b/packages-exp/auth-exp/src/api/index.ts @@ -21,7 +21,12 @@ import { AUTH_ERROR_FACTORY, AuthErrorCode } from '../core/errors'; import { Delay } from '../core/util/delay'; import { Auth } from '../model/auth'; import { IdTokenResponse } from '../model/id_token'; -import { JsonError, SERVER_ERROR_MAP, ServerError, ServerErrorMap } from './errors'; +import { + JsonError, + SERVER_ERROR_MAP, + ServerError, + ServerErrorMap +} from './errors'; export enum HttpMethod { POST = 'POST', @@ -158,8 +163,9 @@ function makeNetworkTimeout(appName: string): Promise { setTimeout(() => { return reject( AUTH_ERROR_FACTORY.create(AuthErrorCode.TIMEOUT, { - appName, + appName }) ); - }, DEFAULT_API_TIMEOUT_MS.get())); + }, DEFAULT_API_TIMEOUT_MS.get()) + ); }