From 54db430cb72abd584512a36427287d703a428295 Mon Sep 17 00:00:00 2001 From: mansisampat Date: Tue, 13 May 2025 14:15:50 +0530 Subject: [PATCH 01/11] Throw Operation Not Allowed for Invalid Auth Endpoint (#9013) (#9019) From 251353f92230b9520fb3c5090e63325b570e8998 Mon Sep 17 00:00:00 2001 From: mansisampat Date: Tue, 13 May 2025 14:15:50 +0530 Subject: [PATCH 02/11] Throw Operation Not Allowed for Invalid Auth Endpoint (#9013) (#9019) From 8690a0141851eabb3e3d681110b6063d852d91aa Mon Sep 17 00:00:00 2001 From: mansisampat Date: Wed, 14 May 2025 18:06:28 +0530 Subject: [PATCH 03/11] Implement exchangeToken public api --- common/api-review/auth.api.md | 3 + docs-devsite/auth.md | 29 +++++ .../api/authentication/exchange_token.test.ts | 101 ++++++++++++++++ .../src/api/authentication/exchange_token.ts | 45 +++++++ packages/auth/src/api/index.test.ts | 3 +- packages/auth/src/api/index.ts | 88 +++++++++----- packages/auth/src/core/auth/auth_impl.ts | 2 +- packages/auth/src/core/index.ts | 1 + .../core/strategies/exchange_token.test.ts | 110 ++++++++++++++++++ .../auth/src/core/strategies/exhange_token.ts | 69 +++++++++++ packages/auth/test/helpers/api/helper.ts | 12 +- packages/auth/test/helpers/mock_auth.ts | 4 +- 12 files changed, 434 insertions(+), 33 deletions(-) create mode 100644 packages/auth/src/api/authentication/exchange_token.test.ts create mode 100644 packages/auth/src/api/authentication/exchange_token.ts create mode 100644 packages/auth/src/core/strategies/exchange_token.test.ts create mode 100644 packages/auth/src/core/strategies/exhange_token.ts diff --git a/common/api-review/auth.api.md b/common/api-review/auth.api.md index 27203e95f3a..ef28f329f56 100644 --- a/common/api-review/auth.api.md +++ b/common/api-review/auth.api.md @@ -364,6 +364,9 @@ export interface EmulatorConfig { export { ErrorFn } +// @public (undocumented) +export function exchangeToken(auth: Auth, idpConfigId: string, customToken: string): Promise; + // Warning: (ae-forgotten-export) The symbol "BaseOAuthProvider" needs to be exported by the entry point index.d.ts // // @public diff --git a/docs-devsite/auth.md b/docs-devsite/auth.md index 6e87e5c1110..615f8915c5e 100644 --- a/docs-devsite/auth.md +++ b/docs-devsite/auth.md @@ -28,6 +28,7 @@ Firebase Authentication | [confirmPasswordReset(auth, oobCode, newPassword)](./auth.md#confirmpasswordreset_749dad8) | Completes the password reset process, given a confirmation code and new password. | | [connectAuthEmulator(auth, url, options)](./auth.md#connectauthemulator_657c7e5) | Changes the [Auth](./auth.auth.md#auth_interface) instance to communicate with the Firebase Auth Emulator, instead of production Firebase Auth services. | | [createUserWithEmailAndPassword(auth, email, password)](./auth.md#createuserwithemailandpassword_21ad33b) | Creates a new user account associated with the specified email address and password. | +| [exchangeToken(auth, idpConfigId, customToken)](./auth.md#exchangetoken_b6b1871) | Asynchronously exchanges an OIDC provider's Authorization code or Id Token for an OidcToken i.e. Outbound Access Token. | | [fetchSignInMethodsForEmail(auth, email)](./auth.md#fetchsigninmethodsforemail_efb3887) | Gets the list of possible sign in methods for the given email address. This method returns an empty list when [Email Enumeration Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled, irrespective of the number of authentication methods available for the given email. | | [getMultiFactorResolver(auth, error)](./auth.md#getmultifactorresolver_201ba61) | Provides a [MultiFactorResolver](./auth.multifactorresolver.md#multifactorresolver_interface) suitable for completion of a multi-factor flow. | | [getRedirectResult(auth, resolver)](./auth.md#getredirectresult_c35dc1f) | Returns a [UserCredential](./auth.usercredential.md#usercredential_interface) from the redirect-based sign-in flow. | @@ -405,6 +406,34 @@ export declare function createUserWithEmailAndPassword(auth: Auth, email: string Promise<[UserCredential](./auth.usercredential.md#usercredential_interface)> +### exchangeToken(auth, idpConfigId, customToken) {:#exchangetoken_b6b1871} + +Asynchronously exchanges an OIDC provider's Authorization code or Id Token for an OidcToken i.e. Outbound Access Token. + +This method is imeplemented only for and requires [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) to be configured in the [Auth](./auth.auth.md#auth_interface) instance used. + +Fails with an error if the token is invalid, expired, or not accepted by the Firebase Auth service. + +Signature: + +```typescript +export declare function exchangeToken(auth: Auth, idpConfigId: string, customToken: string): Promise; +``` + +#### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| auth | [Auth](./auth.auth.md#auth_interface) | The [Auth](./auth.auth.md#auth_interface) instance. | +| idpConfigId | string | The ExternalUserDirectoryId corresponding to the OIDC custom Token. | +| customToken | string | The OIDC provider's Authorization code or Id Token to exchange. | + +Returns: + +Promise<string> + +The firebase access token (JWT signed by Firebase Auth). + ### fetchSignInMethodsForEmail(auth, email) {:#fetchsigninmethodsforemail_efb3887} Gets the list of possible sign in methods for the given email address. This method returns an empty list when [Email Enumeration Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled, irrespective of the number of authentication methods available for the given email. diff --git a/packages/auth/src/api/authentication/exchange_token.test.ts b/packages/auth/src/api/authentication/exchange_token.test.ts new file mode 100644 index 00000000000..abea055e984 --- /dev/null +++ b/packages/auth/src/api/authentication/exchange_token.test.ts @@ -0,0 +1,101 @@ +/** + * @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 chaiAsPromised from 'chai-as-promised'; + +import { + regionalTestAuth, + testAuth, + TestAuth +} from '../../../test/helpers/mock_auth'; +import * as mockFetch from '../../../test/helpers/mock_fetch'; +import { mockRegionalEndpointWithParent } from '../../../test/helpers/api/helper'; +import { exchangeToken } from './exchange_token'; +import { HttpHeader, RegionalEndpoint } from '..'; +import { FirebaseError } from '@firebase/util'; +import { ServerError } from '../errors'; + +use(chaiAsPromised); + +describe('api/authentication/exchange_token', () => { + let auth: TestAuth; + let regionalAuth: TestAuth; + const request = { + parent: 'test-parent', + token: 'custom-token' + }; + + beforeEach(async () => { + auth = await testAuth(); + regionalAuth = await regionalTestAuth(); + mockFetch.setUp(); + }); + + afterEach(mockFetch.tearDown); + + it('returns accesss token for Regional Auth', async () => { + const mock = mockRegionalEndpointWithParent( + RegionalEndpoint.EXCHANGE_TOKEN, + 'test-parent', + { accessToken: 'outbound-token' } + ); + + const response = await exchangeToken(regionalAuth, request); + expect(response.accessToken).equal('outbound-token'); + expect(mock.calls[0].request).to.eql({ + parent: 'test-parent', + token: 'custom-token' + }); + expect(mock.calls[0].method).to.eq('POST'); + expect(mock.calls[0].headers!.get(HttpHeader.CONTENT_TYPE)).to.eq( + 'application/json' + ); + }); + + it('throws exception for default Auth', async () => { + await expect(exchangeToken(auth, request)).to.be.rejectedWith( + FirebaseError, + 'Firebase: Operations not allowed for the auth object initialized. (auth/operation-not-allowed).' + ); + }); + + it('should handle errors', async () => { + const mock = mockRegionalEndpointWithParent( + RegionalEndpoint.EXCHANGE_TOKEN, + 'test-parent', + { + error: { + code: 400, + message: ServerError.INVALID_CUSTOM_TOKEN, + errors: [ + { + message: ServerError.INVALID_CUSTOM_TOKEN + } + ] + } + }, + 400 + ); + + await expect(exchangeToken(regionalAuth, request)).to.be.rejectedWith( + FirebaseError, + '(auth/invalid-custom-token).' + ); + expect(mock.calls[0].request).to.eql(request); + }); +}); diff --git a/packages/auth/src/api/authentication/exchange_token.ts b/packages/auth/src/api/authentication/exchange_token.ts new file mode 100644 index 00000000000..9b58d301b80 --- /dev/null +++ b/packages/auth/src/api/authentication/exchange_token.ts @@ -0,0 +1,45 @@ +/** + * @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 { + RegionalEndpoint, + HttpMethod, + _performRegionalApiRequest +} from '../index'; +import { Auth } from '../../model/public_types'; + +export interface ExchangeTokenRequest { + parent: string; + token: string; +} + +export interface ExchangeTokenRespose { + accessToken: string; +} + +export async function exchangeToken( + auth: Auth, + request: ExchangeTokenRequest +): Promise { + return _performRegionalApiRequest( + auth, + HttpMethod.POST, + RegionalEndpoint.EXCHANGE_TOKEN, + request, + {}, + request.parent + ); +} diff --git a/packages/auth/src/api/index.test.ts b/packages/auth/src/api/index.test.ts index 87f674807c0..1d8e2558d4e 100644 --- a/packages/auth/src/api/index.test.ts +++ b/packages/auth/src/api/index.test.ts @@ -36,6 +36,7 @@ import { ConfigInternal } from '../model/auth'; import { _getFinalTarget, _performApiRequest, + _performRegionalApiRequest, DEFAULT_API_TIMEOUT_MS, Endpoint, RegionalEndpoint, @@ -606,7 +607,7 @@ describe('api/_performApiRequest', () => { context('throws Operation not allowed exception', () => { it('when tenantConfig is not initialized and Regional Endpoint is used', async () => { await expect( - _performApiRequest( + _performRegionalApiRequest( auth, HttpMethod.POST, RegionalEndpoint.EXCHANGE_TOKEN, diff --git a/packages/auth/src/api/index.ts b/packages/auth/src/api/index.ts index a1480803449..ec3c7662194 100644 --- a/packages/auth/src/api/index.ts +++ b/packages/auth/src/api/index.ts @@ -54,7 +54,7 @@ export const enum HttpHeader { X_FIREBASE_APP_CHECK = 'X-Firebase-AppCheck' } -export enum Endpoint { +export const enum Endpoint { CREATE_AUTH_URI = '/v1/accounts:createAuthUri', DELETE_ACCOUNT = '/v1/accounts:delete', RESET_PASSWORD = '/v1/accounts:resetPassword', @@ -81,8 +81,11 @@ export enum Endpoint { REVOKE_TOKEN = '/v2/accounts:revokeToken' } -export enum RegionalEndpoint { - EXCHANGE_TOKEN = 'v2/${body.parent}:exchangeOidcToken' +export const EXCHANGE_TOKEN_PARENT = + 'projects/${projectId}/locations/${location}/tenants/${tenantId}/idpConfigs/${idpConfigId}'; + +export const enum RegionalEndpoint { + EXCHANGE_TOKEN = ':exchangeOidcToken' } const CookieAuthProxiedEndpoints: string[] = [ @@ -141,14 +144,17 @@ export function _addTidIfNecessary( return request; } -export async function _performApiRequest( +function isRegionalAuthInitialized(auth: Auth): boolean { + return !!auth.tenantConfig; +} + +async function performApiRequest( auth: Auth, method: HttpMethod, - path: Endpoint | RegionalEndpoint, + path: string, request?: T, customErrorMap: Partial> = {} ): Promise { - _assertValidEndpointForAuth(auth, path); return _performFetchWithErrorHandling(auth, customErrorMap, async () => { let body = {}; let params = {}; @@ -162,10 +168,17 @@ export async function _performApiRequest( } } - const query = querystring({ - key: auth.config.apiKey, - ...params - }).slice(1); + let queryParamString: string; + if (isRegionalAuthInitialized(auth)) { + queryParamString = querystring({ + ...params + }).slice(1); + } else { + queryParamString = querystring({ + key: auth.config.apiKey, + ...params + }).slice(1); + } const headers = await (auth as AuthInternal)._getAdditionalHeaders(); headers[HttpHeader.CONTENT_TYPE] = 'application/json'; @@ -193,12 +206,45 @@ export async function _performApiRequest( } return FetchProvider.fetch()( - await _getFinalTarget(auth, auth.config.apiHost, path, query), + await _getFinalTarget(auth, auth.config.apiHost, path, queryParamString), fetchArgs ); }); } +export async function _performRegionalApiRequest( + auth: Auth, + method: HttpMethod, + path: RegionalEndpoint, + request?: T, + customErrorMap: Partial> = {}, + parent?: string +): Promise { + if (!isRegionalAuthInitialized(auth)) { + throw _operationNotSupportedForInitializedAuthInstance(auth); + } + return performApiRequest( + auth, + method, + `${parent}${path}`, + request, + customErrorMap + ); +} + +export async function _performApiRequest( + auth: Auth, + method: HttpMethod, + path: Endpoint, + request?: T, + customErrorMap: Partial> = {} +): Promise { + if (isRegionalAuthInitialized(auth)) { + throw _operationNotSupportedForInitializedAuthInstance(auth); + } + return performApiRequest(auth, method, `${path}`, request, customErrorMap); +} + export async function _performFetchWithErrorHandling( auth: Auth, customErrorMap: Partial>, @@ -287,9 +333,9 @@ export async function _getFinalTarget( auth: Auth, host: string, path: string, - query: string + query?: string ): Promise { - const base = `${host}${path}?${query}`; + const base = query ? `${host}${path}?${query}` : `${host}${path}`; const authInternal = auth as AuthInternal; const finalTarget = authInternal.config.emulator @@ -328,22 +374,6 @@ export function _parseEnforcementState( } } -function _assertValidEndpointForAuth( - auth: Auth, - path: Endpoint | RegionalEndpoint -): void { - if ( - !auth.tenantConfig && - Object.values(RegionalEndpoint).includes(path as RegionalEndpoint) - ) { - throw _operationNotSupportedForInitializedAuthInstance(auth); - } - - if (auth.tenantConfig && Object.values(Endpoint).includes(path as Endpoint)) { - throw _operationNotSupportedForInitializedAuthInstance(auth); - } -} - class NetworkTimeout { // Node timers and browser timers are fundamentally incompatible, but we // don't care about the value here diff --git a/packages/auth/src/core/auth/auth_impl.ts b/packages/auth/src/core/auth/auth_impl.ts index d21cfdd0214..8aac4fb12f4 100644 --- a/packages/auth/src/core/auth/auth_impl.ts +++ b/packages/auth/src/core/auth/auth_impl.ts @@ -93,7 +93,7 @@ export const enum DefaultConfig { TOKEN_API_HOST = 'securetoken.googleapis.com', API_HOST = 'identitytoolkit.googleapis.com', API_SCHEME = 'https', - REGIONAL_API_HOST = 'identityplatform.googleapis.com' + REGIONAL_API_HOST = 'identityplatform.googleapis.com/v2alpha/' } export class AuthImpl implements AuthInternal, _FirebaseService { diff --git a/packages/auth/src/core/index.ts b/packages/auth/src/core/index.ts index 43b1adb4bb9..e3b0e3b55a1 100644 --- a/packages/auth/src/core/index.ts +++ b/packages/auth/src/core/index.ts @@ -315,6 +315,7 @@ export { sendEmailVerification, verifyBeforeUpdateEmail } from './strategies/email'; +export { exchangeToken } from './strategies/exhange_token'; // core export { ActionCodeURL, parseActionCodeURL } from './action_code_url'; diff --git a/packages/auth/src/core/strategies/exchange_token.test.ts b/packages/auth/src/core/strategies/exchange_token.test.ts new file mode 100644 index 00000000000..fce2172d148 --- /dev/null +++ b/packages/auth/src/core/strategies/exchange_token.test.ts @@ -0,0 +1,110 @@ +/** + * @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 chaiAsPromised from 'chai-as-promised'; + +import { mockRegionalEndpointWithParent } from '../../../test/helpers/api/helper'; +import { + regionalTestAuth, + testAuth, + TestAuth +} from '../../../test/helpers/mock_auth'; +import * as mockFetch from '../../../test/helpers/mock_fetch'; +import { HttpHeader, RegionalEndpoint } from '../../api'; +import { exchangeToken } from './exhange_token'; +import { FirebaseError } from '@firebase/util'; +import { ServerError } from '../../api/errors'; + +use(chaiAsPromised); + +describe('core/strategies/exchangeToken', () => { + let auth: TestAuth; + let regionalAuth: TestAuth; + + beforeEach(async () => { + auth = await testAuth(); + regionalAuth = await regionalTestAuth(); + mockFetch.setUp(); + }); + afterEach(mockFetch.tearDown); + + it('should return a valid access token for Regional Auth', async () => { + const mock = mockRegionalEndpointWithParent( + RegionalEndpoint.EXCHANGE_TOKEN, + 'projects/test-project-id/locations/us/tenants/tenant-1/idpConfigs/idp-config', + { accessToken: 'outbound-token' } + ); + + const accessToken = await exchangeToken( + regionalAuth, + 'idp-config', + 'custom-token' + ); + expect(accessToken).to.eq('outbound-token'); + expect(mock.calls[0].request).to.eql({ + parent: + 'projects/test-project-id/locations/us/tenants/tenant-1/idpConfigs/idp-config', + token: 'custom-token' + }); + expect(mock.calls[0].method).to.eq('POST'); + expect(mock.calls[0].headers!.get(HttpHeader.CONTENT_TYPE)).to.eq( + 'application/json' + ); + }); + + it('throws exception for default Auth', async () => { + await expect( + exchangeToken(auth, 'idp-config', 'custom-token') + ).to.be.rejectedWith( + FirebaseError, + 'Firebase: Operations not allowed for the auth object initialized. (auth/operation-not-allowed).' + ); + }); + + it('should handle errors', async () => { + const mock = mockRegionalEndpointWithParent( + RegionalEndpoint.EXCHANGE_TOKEN, + 'projects/test-project-id/locations/us/tenants/tenant-1/idpConfigs/idp-config', + { + error: { + code: 400, + message: ServerError.INVALID_CUSTOM_TOKEN, + errors: [ + { + message: ServerError.INVALID_CUSTOM_TOKEN + } + ] + } + }, + 400 + ); + + await expect( + exchangeToken(regionalAuth, 'idp-config', 'custom-token') + ).to.be.rejectedWith(FirebaseError, '(auth/invalid-custom-token).'); + expect(mock.calls[0].request).to.eql({ + parent: + 'projects/test-project-id/locations/us/tenants/tenant-1/idpConfigs/idp-config', + token: 'custom-token' + }); + expect(mock.calls[0].method).to.eq('POST'); + expect(mock.calls[0].headers!.get(HttpHeader.CONTENT_TYPE)).to.eq( + 'application/json' + ); + }); +}); diff --git a/packages/auth/src/core/strategies/exhange_token.ts b/packages/auth/src/core/strategies/exhange_token.ts new file mode 100644 index 00000000000..d0f128b979d --- /dev/null +++ b/packages/auth/src/core/strategies/exhange_token.ts @@ -0,0 +1,69 @@ +/** + * @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 { Auth } from '../../model/public_types'; +import { _isFirebaseServerApp } from '@firebase/app'; +import { exchangeToken as getToken } from '../../api/authentication/exchange_token'; +import { _serverAppCurrentUserOperationNotSupportedError } from '../../core/util/assert'; +import { EXCHANGE_TOKEN_PARENT } from '../../api'; +import { _castAuth } from '../auth/auth_impl'; + +/** + * Asynchronously exchanges an OIDC provider's Authorization code or Id Token + * for an OidcToken i.e. Outbound Access Token. + * + * @remarks + * This method is imeplemented only for {@link DefaultConfig.REGIONAL_API_HOST} + * and requires {@link TenantConfig} to be configured in the {@link Auth} instance used. + * + * Fails with an error if the token is invalid, expired, or not accepted by the Firebase Auth service. + * + * @param auth - The {@link Auth} instance. + * @param idpConfigId - The ExternalUserDirectoryId corresponding to the OIDC custom Token. + * @param customToken - The OIDC provider's Authorization code or Id Token to exchange. + * @returns The firebase access token (JWT signed by Firebase Auth). + * + * @public + */ +export async function exchangeToken( + auth: Auth, + idpConfigId: string, + customToken: string +): Promise { + if (_isFirebaseServerApp(auth.app)) { + return Promise.reject( + _serverAppCurrentUserOperationNotSupportedError(auth) + ); + } + const authInternal = _castAuth(auth); + const token = await getToken(authInternal, { + parent: buildParent(auth, idpConfigId), + token: customToken + }); + // TODO(sammansi): Write token to the Auth object passed. + return token.accessToken; +} + +function buildParent(auth: Auth, idpConfigId: string): string { + return EXCHANGE_TOKEN_PARENT.replace( + '${projectId}', + auth.app.options.projectId ?? '' + ) + .replace('${location}', auth.tenantConfig?.location ?? '') + .replace('${tenantId}', auth.tenantConfig?.tenantId ?? '') + .replace('${idpConfigId}', idpConfigId); +} diff --git a/packages/auth/test/helpers/api/helper.ts b/packages/auth/test/helpers/api/helper.ts index 638310b139e..00680be3341 100644 --- a/packages/auth/test/helpers/api/helper.ts +++ b/packages/auth/test/helpers/api/helper.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { Endpoint } from '../../../src/api'; +import { Endpoint, RegionalEndpoint } from '../../../src/api'; import { TEST_HOST, TEST_KEY, TEST_SCHEME } from '../mock_auth'; import { mock, Route } from '../mock_fetch'; @@ -55,3 +55,13 @@ export function mockEndpointWithParams( ): Route { return mock(endpointUrlWithParams(endpoint, params), response, status); } + +export function mockRegionalEndpointWithParent( + endpoint: RegionalEndpoint, + parent: string, + response: object, + status = 200 +): Route { + const url = `${TEST_SCHEME}://${TEST_HOST}${parent}${endpoint}`; + return mock(url, response, status); +} diff --git a/packages/auth/test/helpers/mock_auth.ts b/packages/auth/test/helpers/mock_auth.ts index 15c03dc42c1..68e155a88f4 100644 --- a/packages/auth/test/helpers/mock_auth.ts +++ b/packages/auth/test/helpers/mock_auth.ts @@ -42,7 +42,9 @@ export interface TestAuth extends AuthImpl { const FAKE_APP: FirebaseApp = { name: 'test-app', - options: {}, + options: { + projectId: 'test-project-id' + }, automaticDataCollectionEnabled: false }; From 8965130de991ee0f2512910a9ca1bb5ce0692d96 Mon Sep 17 00:00:00 2001 From: mansisampat Date: Thu, 15 May 2025 17:39:02 +0530 Subject: [PATCH 04/11] Using expiry_in returned by backend --- packages/auth/src/api/authentication/exchange_token.test.ts | 3 ++- packages/auth/src/api/authentication/exchange_token.ts | 1 + packages/auth/src/core/strategies/exchange_token.test.ts | 2 +- packages/auth/src/core/strategies/exhange_token.ts | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/auth/src/api/authentication/exchange_token.test.ts b/packages/auth/src/api/authentication/exchange_token.test.ts index abea055e984..0b3c2f66049 100644 --- a/packages/auth/src/api/authentication/exchange_token.test.ts +++ b/packages/auth/src/api/authentication/exchange_token.test.ts @@ -52,11 +52,12 @@ describe('api/authentication/exchange_token', () => { const mock = mockRegionalEndpointWithParent( RegionalEndpoint.EXCHANGE_TOKEN, 'test-parent', - { accessToken: 'outbound-token' } + { accessToken: 'outbound-token', expiresIn: '1000' } ); const response = await exchangeToken(regionalAuth, request); expect(response.accessToken).equal('outbound-token'); + expect(response.expiresIn).equal('1000'); expect(mock.calls[0].request).to.eql({ parent: 'test-parent', token: 'custom-token' diff --git a/packages/auth/src/api/authentication/exchange_token.ts b/packages/auth/src/api/authentication/exchange_token.ts index 9b58d301b80..01a8c5e6a79 100644 --- a/packages/auth/src/api/authentication/exchange_token.ts +++ b/packages/auth/src/api/authentication/exchange_token.ts @@ -28,6 +28,7 @@ export interface ExchangeTokenRequest { export interface ExchangeTokenRespose { accessToken: string; + expiresIn?: string; } export async function exchangeToken( diff --git a/packages/auth/src/core/strategies/exchange_token.test.ts b/packages/auth/src/core/strategies/exchange_token.test.ts index fce2172d148..19dc245b44e 100644 --- a/packages/auth/src/core/strategies/exchange_token.test.ts +++ b/packages/auth/src/core/strategies/exchange_token.test.ts @@ -47,7 +47,7 @@ describe('core/strategies/exchangeToken', () => { const mock = mockRegionalEndpointWithParent( RegionalEndpoint.EXCHANGE_TOKEN, 'projects/test-project-id/locations/us/tenants/tenant-1/idpConfigs/idp-config', - { accessToken: 'outbound-token' } + { accessToken: 'outbound-token', expiresIn: '1000' } ); const accessToken = await exchangeToken( diff --git a/packages/auth/src/core/strategies/exhange_token.ts b/packages/auth/src/core/strategies/exhange_token.ts index d0f128b979d..b423d82d484 100644 --- a/packages/auth/src/core/strategies/exhange_token.ts +++ b/packages/auth/src/core/strategies/exhange_token.ts @@ -27,7 +27,7 @@ import { _castAuth } from '../auth/auth_impl'; * for an OidcToken i.e. Outbound Access Token. * * @remarks - * This method is imeplemented only for {@link DefaultConfig.REGIONAL_API_HOST} + * This method is implemented only for {@link DefaultConfig.REGIONAL_API_HOST} * and requires {@link TenantConfig} to be configured in the {@link Auth} instance used. * * Fails with an error if the token is invalid, expired, or not accepted by the Firebase Auth service. From 978f78f58ade50906c682e0f26e72a65e1ff305f Mon Sep 17 00:00:00 2001 From: mansisampat Date: Thu, 22 May 2025 10:23:40 +0530 Subject: [PATCH 05/11] Addressing review comments and adding some Unit test --- .../api/authentication/exchange_token.test.ts | 2 +- .../src/api/authentication/exchange_token.ts | 2 +- packages/auth/src/api/index.test.ts | 108 ++++++++++++++++-- .../core/strategies/exchange_token.test.ts | 2 +- .../auth/src/core/strategies/exhange_token.ts | 6 +- packages/auth/src/model/public_types.ts | 4 +- packages/auth/test/helpers/api/helper.ts | 1 + 7 files changed, 108 insertions(+), 17 deletions(-) diff --git a/packages/auth/src/api/authentication/exchange_token.test.ts b/packages/auth/src/api/authentication/exchange_token.test.ts index 0b3c2f66049..6a3b1b366e8 100644 --- a/packages/auth/src/api/authentication/exchange_token.test.ts +++ b/packages/auth/src/api/authentication/exchange_token.test.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2020 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/auth/src/api/authentication/exchange_token.ts b/packages/auth/src/api/authentication/exchange_token.ts index 01a8c5e6a79..dde1b8f9b2f 100644 --- a/packages/auth/src/api/authentication/exchange_token.ts +++ b/packages/auth/src/api/authentication/exchange_token.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2020 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/auth/src/api/index.test.ts b/packages/auth/src/api/index.test.ts index 1d8e2558d4e..614956abb4e 100644 --- a/packages/auth/src/api/index.test.ts +++ b/packages/auth/src/api/index.test.ts @@ -24,7 +24,10 @@ import sinonChai from 'sinon-chai'; import { FirebaseError, getUA } from '@firebase/util'; import * as utils from '@firebase/util'; -import { mockEndpoint } from '../../test/helpers/api/helper'; +import { + mockEndpoint, + mockRegionalEndpointWithParent +} from '../../test/helpers/api/helper'; import { regionalTestAuth, testAuth, @@ -605,12 +608,12 @@ describe('api/_performApiRequest', () => { }); context('throws Operation not allowed exception', () => { - it('when tenantConfig is not initialized and Regional Endpoint is used', async () => { + it('when tenantConfig is initialized and default Endpoint is used', async () => { await expect( - _performRegionalApiRequest( - auth, + _performApiRequest( + regionalAuth, HttpMethod.POST, - RegionalEndpoint.EXCHANGE_TOKEN, + Endpoint.SIGN_UP, request ) ).to.be.rejectedWith( @@ -618,13 +621,100 @@ describe('api/_performApiRequest', () => { 'Firebase: Operations not allowed for the auth object initialized. (auth/operation-not-allowed).' ); }); + }); +}); - it('when tenantConfig is initialized and default Endpoint is used', async () => { +describe('api/_performRegionalApiRequest', () => { + const request = { + requestKey: 'request-value' + }; + + const serverResponse = { + responseKey: 'response-value' + }; + + let auth: TestAuth; + let regionalAuth: TestAuth; + + beforeEach(async () => { + auth = await testAuth(); + regionalAuth = await regionalTestAuth(); + }); + + afterEach(() => { + sinon.restore(); + }); + + context('with regular requests', () => { + beforeEach(mockFetch.setUp); + afterEach(mockFetch.tearDown); + it('should set the correct request, method and HTTP Headers', async () => { + const mock = mockRegionalEndpointWithParent( + RegionalEndpoint.EXCHANGE_TOKEN, + 'test-parent', + serverResponse + ); + const response = await _performRegionalApiRequest< + typeof request, + typeof serverResponse + >( + regionalAuth, + HttpMethod.POST, + RegionalEndpoint.EXCHANGE_TOKEN, + request, + {}, + 'test-parent' + ); + expect(response).to.eql(serverResponse); + expect(mock.calls.length).to.eq(1); + expect(mock.calls[0].method).to.eq(HttpMethod.POST); + expect(mock.calls[0].request).to.eql(request); + 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' + ); + expect(mock.calls[0].fullRequest?.credentials).to.be.undefined; + }); + + it('should include whatever headers the auth impl attaches', async () => { + sinon.stub(regionalAuth, '_getAdditionalHeaders').returns( + Promise.resolve({ + 'look-at-me-im-a-header': 'header-value', + 'anotherheader': 'header-value-2' + }) + ); + + const mock = mockRegionalEndpointWithParent( + RegionalEndpoint.EXCHANGE_TOKEN, + 'test-parent', + serverResponse + ); + await _performRegionalApiRequest( + regionalAuth, + HttpMethod.POST, + RegionalEndpoint.EXCHANGE_TOKEN, + request, + {}, + 'test-parent' + ); + expect(mock.calls[0].headers.get('look-at-me-im-a-header')).to.eq( + 'header-value' + ); + expect(mock.calls[0].headers.get('anotherheader')).to.eq( + 'header-value-2' + ); + }); + }); + + context('throws Operation not allowed exception', () => { + it('when tenantConfig is not initialized and Regional Endpoint is used', async () => { await expect( - _performApiRequest( - regionalAuth, + _performRegionalApiRequest( + auth, HttpMethod.POST, - Endpoint.SIGN_UP, + RegionalEndpoint.EXCHANGE_TOKEN, request ) ).to.be.rejectedWith( diff --git a/packages/auth/src/core/strategies/exchange_token.test.ts b/packages/auth/src/core/strategies/exchange_token.test.ts index 19dc245b44e..60166034b64 100644 --- a/packages/auth/src/core/strategies/exchange_token.test.ts +++ b/packages/auth/src/core/strategies/exchange_token.test.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2020 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/auth/src/core/strategies/exhange_token.ts b/packages/auth/src/core/strategies/exhange_token.ts index b423d82d484..8b2c37a2b93 100644 --- a/packages/auth/src/core/strategies/exhange_token.ts +++ b/packages/auth/src/core/strategies/exhange_token.ts @@ -1,6 +1,6 @@ /** * @license - * Copyright 2020 Google LLC + * Copyright 2025 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -27,8 +27,8 @@ import { _castAuth } from '../auth/auth_impl'; * for an OidcToken i.e. Outbound Access Token. * * @remarks - * This method is implemented only for {@link DefaultConfig.REGIONAL_API_HOST} - * and requires {@link TenantConfig} to be configured in the {@link Auth} instance used. + * This method is implemented only for `DefaultConfig.REGIONAL_API_HOST` and + * requires {@link TenantConfig} to be configured in the {@link Auth} instance used. * * Fails with an error if the token is invalid, expired, or not accepted by the Firebase Auth service. * diff --git a/packages/auth/src/model/public_types.ts b/packages/auth/src/model/public_types.ts index bd6c9cc2b8c..e7275aeee4c 100644 --- a/packages/auth/src/model/public_types.ts +++ b/packages/auth/src/model/public_types.ts @@ -185,7 +185,7 @@ export interface Auth { readonly config: Config; /** * The {@link TenantConfig} used to initialize a Regional Auth. This is only present - * if regional auth is initialized and {@link DefaultConfig.REGIONAL_API_HOST} + * if regional auth is initialized and `DefaultConfig.REGIONAL_API_HOST` * backend endpoint is used. */ readonly tenantConfig?: TenantConfig; @@ -1269,7 +1269,7 @@ export interface Dependencies { /** * The {@link TenantConfig} to use. This dependency is only required * if you want to use regional auth which works with - * {@link DefaultConfig.REGIONAL_API_HOST} endpoint. It should not be set otherwise. + * `DefaultConfig.REGIONAL_API_HOST`` endpoint. It should not be set otherwise. */ tenantConfig?: TenantConfig; } diff --git a/packages/auth/test/helpers/api/helper.ts b/packages/auth/test/helpers/api/helper.ts index 00680be3341..1877371bf2e 100644 --- a/packages/auth/test/helpers/api/helper.ts +++ b/packages/auth/test/helpers/api/helper.ts @@ -63,5 +63,6 @@ export function mockRegionalEndpointWithParent( status = 200 ): Route { const url = `${TEST_SCHEME}://${TEST_HOST}${parent}${endpoint}`; + console.log('here ', url); return mock(url, response, status); } From d9ef12550a56c50cdcfcb24dc399fe4ec040a987 Mon Sep 17 00:00:00 2001 From: mansisampat Date: Thu, 22 May 2025 10:45:15 +0530 Subject: [PATCH 06/11] Docgen --- docs-devsite/auth.auth.md | 4 ++-- docs-devsite/auth.dependencies.md | 4 ++-- docs-devsite/auth.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs-devsite/auth.auth.md b/docs-devsite/auth.auth.md index 1f96bd23881..170447bc43c 100644 --- a/docs-devsite/auth.auth.md +++ b/docs-devsite/auth.auth.md @@ -31,7 +31,7 @@ export interface Auth | [languageCode](./auth.auth.md#authlanguagecode) | string \| null | The [Auth](./auth.auth.md#auth_interface) instance's language code. | | [name](./auth.auth.md#authname) | string | The name of the app associated with the Auth service instance. | | [settings](./auth.auth.md#authsettings) | [AuthSettings](./auth.authsettings.md#authsettings_interface) | The [Auth](./auth.auth.md#auth_interface) instance's settings. | -| [tenantConfig](./auth.auth.md#authtenantconfig) | [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) | The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) used to initialize a Regional Auth. This is only present if regional auth is initialized and backend endpoint is used. | +| [tenantConfig](./auth.auth.md#authtenantconfig) | [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) | The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) used to initialize a Regional Auth. This is only present if regional auth is initialized and DefaultConfig.REGIONAL_API_HOST backend endpoint is used. | | [tenantId](./auth.auth.md#authtenantid) | string \| null | The [Auth](./auth.auth.md#auth_interface) instance's tenant ID. | ## Methods @@ -123,7 +123,7 @@ readonly settings: AuthSettings; ## Auth.tenantConfig -The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) used to initialize a Regional Auth. This is only present if regional auth is initialized and backend endpoint is used. +The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) used to initialize a Regional Auth. This is only present if regional auth is initialized and `DefaultConfig.REGIONAL_API_HOST` backend endpoint is used. Signature: diff --git a/docs-devsite/auth.dependencies.md b/docs-devsite/auth.dependencies.md index b80bd24af20..2f63a9c6509 100644 --- a/docs-devsite/auth.dependencies.md +++ b/docs-devsite/auth.dependencies.md @@ -29,7 +29,7 @@ export interface Dependencies | [errorMap](./auth.dependencies.md#dependencieserrormap) | [AuthErrorMap](./auth.autherrormap.md#autherrormap_interface) | Which [AuthErrorMap](./auth.autherrormap.md#autherrormap_interface) to use. | | [persistence](./auth.dependencies.md#dependenciespersistence) | [Persistence](./auth.persistence.md#persistence_interface) \| [Persistence](./auth.persistence.md#persistence_interface)\[\] | Which [Persistence](./auth.persistence.md#persistence_interface) to use. If this is an array, the first Persistence that the device supports is used. The SDK searches for an existing account in order and, if one is found in a secondary Persistence, the account is moved to the primary Persistence.If no persistence is provided, the SDK falls back on [inMemoryPersistence](./auth.md#inmemorypersistence). | | [popupRedirectResolver](./auth.dependencies.md#dependenciespopupredirectresolver) | [PopupRedirectResolver](./auth.popupredirectresolver.md#popupredirectresolver_interface) | The [PopupRedirectResolver](./auth.popupredirectresolver.md#popupredirectresolver_interface) to use. This value depends on the platform. Options are [browserPopupRedirectResolver](./auth.md#browserpopupredirectresolver) and [cordovaPopupRedirectResolver](./auth.md#cordovapopupredirectresolver). This field is optional if neither [signInWithPopup()](./auth.md#signinwithpopup_770f816) or [signInWithRedirect()](./auth.md#signinwithredirect_770f816) are being used. | -| [tenantConfig](./auth.dependencies.md#dependenciestenantconfig) | [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) | The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) to use. This dependency is only required if you want to use regional auth which works with endpoint. It should not be set otherwise. | +| [tenantConfig](./auth.dependencies.md#dependenciestenantconfig) | [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) | The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) to use. This dependency is only required if you want to use regional auth which works with DefaultConfig.REGIONAL_API_HOST\` endpoint. It should not be set otherwise. | ## Dependencies.errorMap @@ -65,7 +65,7 @@ popupRedirectResolver?: PopupRedirectResolver; ## Dependencies.tenantConfig -The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) to use. This dependency is only required if you want to use regional auth which works with endpoint. It should not be set otherwise. +The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) to use. This dependency is only required if you want to use regional auth which works with `DefaultConfig.REGIONAL_API_HOST` endpoint. It should not be set otherwise. Signature: diff --git a/docs-devsite/auth.md b/docs-devsite/auth.md index 615f8915c5e..ab460d58e51 100644 --- a/docs-devsite/auth.md +++ b/docs-devsite/auth.md @@ -410,7 +410,7 @@ Promise<[UserCredential](./auth.usercredential.md#usercredential_interface) Date: Thu, 22 May 2025 11:40:11 +0530 Subject: [PATCH 07/11] Addressing review comments and adding some Unit test --- packages/auth/src/core/auth/auth_impl.ts | 1 + packages/auth/src/core/strategies/exhange_token.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/auth/src/core/auth/auth_impl.ts b/packages/auth/src/core/auth/auth_impl.ts index 8aac4fb12f4..7e18b7d44e0 100644 --- a/packages/auth/src/core/auth/auth_impl.ts +++ b/packages/auth/src/core/auth/auth_impl.ts @@ -93,6 +93,7 @@ export const enum DefaultConfig { TOKEN_API_HOST = 'securetoken.googleapis.com', API_HOST = 'identitytoolkit.googleapis.com', API_SCHEME = 'https', + // TODO(sammansi): Update the endpoint before BYO-CIAM Private Preview Release. REGIONAL_API_HOST = 'identityplatform.googleapis.com/v2alpha/' } diff --git a/packages/auth/src/core/strategies/exhange_token.ts b/packages/auth/src/core/strategies/exhange_token.ts index 8b2c37a2b93..6b4c11b8017 100644 --- a/packages/auth/src/core/strategies/exhange_token.ts +++ b/packages/auth/src/core/strategies/exhange_token.ts @@ -24,7 +24,7 @@ import { _castAuth } from '../auth/auth_impl'; /** * Asynchronously exchanges an OIDC provider's Authorization code or Id Token - * for an OidcToken i.e. Outbound Access Token. + * for a Firebase Token. * * @remarks * This method is implemented only for `DefaultConfig.REGIONAL_API_HOST` and From 395494a0e8455a548968a3deb5492dbf224d5d04 Mon Sep 17 00:00:00 2001 From: mansisampat Date: Thu, 22 May 2025 11:46:06 +0530 Subject: [PATCH 08/11] Typo --- packages/auth/src/model/public_types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/auth/src/model/public_types.ts b/packages/auth/src/model/public_types.ts index e7275aeee4c..353064af467 100644 --- a/packages/auth/src/model/public_types.ts +++ b/packages/auth/src/model/public_types.ts @@ -1269,7 +1269,7 @@ export interface Dependencies { /** * The {@link TenantConfig} to use. This dependency is only required * if you want to use regional auth which works with - * `DefaultConfig.REGIONAL_API_HOST`` endpoint. It should not be set otherwise. + * `DefaultConfig.REGIONAL_API_HOST` endpoint. It should not be set otherwise. */ tenantConfig?: TenantConfig; } From c20bb3f656a831a615a7340ec9ed9ca7137d40a2 Mon Sep 17 00:00:00 2001 From: mansisampat Date: Thu, 22 May 2025 11:52:47 +0530 Subject: [PATCH 09/11] yarn docgen --- docs-devsite/auth.dependencies.md | 2 +- docs-devsite/auth.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs-devsite/auth.dependencies.md b/docs-devsite/auth.dependencies.md index 2f63a9c6509..d5b098cbedd 100644 --- a/docs-devsite/auth.dependencies.md +++ b/docs-devsite/auth.dependencies.md @@ -29,7 +29,7 @@ export interface Dependencies | [errorMap](./auth.dependencies.md#dependencieserrormap) | [AuthErrorMap](./auth.autherrormap.md#autherrormap_interface) | Which [AuthErrorMap](./auth.autherrormap.md#autherrormap_interface) to use. | | [persistence](./auth.dependencies.md#dependenciespersistence) | [Persistence](./auth.persistence.md#persistence_interface) \| [Persistence](./auth.persistence.md#persistence_interface)\[\] | Which [Persistence](./auth.persistence.md#persistence_interface) to use. If this is an array, the first Persistence that the device supports is used. The SDK searches for an existing account in order and, if one is found in a secondary Persistence, the account is moved to the primary Persistence.If no persistence is provided, the SDK falls back on [inMemoryPersistence](./auth.md#inmemorypersistence). | | [popupRedirectResolver](./auth.dependencies.md#dependenciespopupredirectresolver) | [PopupRedirectResolver](./auth.popupredirectresolver.md#popupredirectresolver_interface) | The [PopupRedirectResolver](./auth.popupredirectresolver.md#popupredirectresolver_interface) to use. This value depends on the platform. Options are [browserPopupRedirectResolver](./auth.md#browserpopupredirectresolver) and [cordovaPopupRedirectResolver](./auth.md#cordovapopupredirectresolver). This field is optional if neither [signInWithPopup()](./auth.md#signinwithpopup_770f816) or [signInWithRedirect()](./auth.md#signinwithredirect_770f816) are being used. | -| [tenantConfig](./auth.dependencies.md#dependenciestenantconfig) | [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) | The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) to use. This dependency is only required if you want to use regional auth which works with DefaultConfig.REGIONAL_API_HOST\` endpoint. It should not be set otherwise. | +| [tenantConfig](./auth.dependencies.md#dependenciestenantconfig) | [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) | The [TenantConfig](./auth.tenantconfig.md#tenantconfig_interface) to use. This dependency is only required if you want to use regional auth which works with DefaultConfig.REGIONAL_API_HOST endpoint. It should not be set otherwise. | ## Dependencies.errorMap diff --git a/docs-devsite/auth.md b/docs-devsite/auth.md index ab460d58e51..9b8a294ede4 100644 --- a/docs-devsite/auth.md +++ b/docs-devsite/auth.md @@ -28,7 +28,7 @@ Firebase Authentication | [confirmPasswordReset(auth, oobCode, newPassword)](./auth.md#confirmpasswordreset_749dad8) | Completes the password reset process, given a confirmation code and new password. | | [connectAuthEmulator(auth, url, options)](./auth.md#connectauthemulator_657c7e5) | Changes the [Auth](./auth.auth.md#auth_interface) instance to communicate with the Firebase Auth Emulator, instead of production Firebase Auth services. | | [createUserWithEmailAndPassword(auth, email, password)](./auth.md#createuserwithemailandpassword_21ad33b) | Creates a new user account associated with the specified email address and password. | -| [exchangeToken(auth, idpConfigId, customToken)](./auth.md#exchangetoken_b6b1871) | Asynchronously exchanges an OIDC provider's Authorization code or Id Token for an OidcToken i.e. Outbound Access Token. | +| [exchangeToken(auth, idpConfigId, customToken)](./auth.md#exchangetoken_b6b1871) | Asynchronously exchanges an OIDC provider's Authorization code or Id Token for a Firebase Token. | | [fetchSignInMethodsForEmail(auth, email)](./auth.md#fetchsigninmethodsforemail_efb3887) | Gets the list of possible sign in methods for the given email address. This method returns an empty list when [Email Enumeration Protection](https://cloud.google.com/identity-platform/docs/admin/email-enumeration-protection) is enabled, irrespective of the number of authentication methods available for the given email. | | [getMultiFactorResolver(auth, error)](./auth.md#getmultifactorresolver_201ba61) | Provides a [MultiFactorResolver](./auth.multifactorresolver.md#multifactorresolver_interface) suitable for completion of a multi-factor flow. | | [getRedirectResult(auth, resolver)](./auth.md#getredirectresult_c35dc1f) | Returns a [UserCredential](./auth.usercredential.md#usercredential_interface) from the redirect-based sign-in flow. | @@ -408,7 +408,7 @@ Promise<[UserCredential](./auth.usercredential.md#usercredential_interface) Date: Fri, 23 May 2025 10:17:41 +0530 Subject: [PATCH 10/11] Fixing typo --- packages/auth/src/api/authentication/exchange_token.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/auth/src/api/authentication/exchange_token.ts b/packages/auth/src/api/authentication/exchange_token.ts index dde1b8f9b2f..20edc326f23 100644 --- a/packages/auth/src/api/authentication/exchange_token.ts +++ b/packages/auth/src/api/authentication/exchange_token.ts @@ -26,7 +26,7 @@ export interface ExchangeTokenRequest { token: string; } -export interface ExchangeTokenRespose { +export interface ExchangeTokenResponse { accessToken: string; expiresIn?: string; } @@ -34,8 +34,8 @@ export interface ExchangeTokenRespose { export async function exchangeToken( auth: Auth, request: ExchangeTokenRequest -): Promise { - return _performRegionalApiRequest( +): Promise { + return _performRegionalApiRequest( auth, HttpMethod.POST, RegionalEndpoint.EXCHANGE_TOKEN, From 14bb1cdd3ff3b2625184b9cb7ce344144acc63b2 Mon Sep 17 00:00:00 2001 From: mansisampat Date: Fri, 23 May 2025 10:34:24 +0530 Subject: [PATCH 11/11] yarn run format --- packages/auth/src/api/authentication/exchange_token.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/auth/src/api/authentication/exchange_token.ts b/packages/auth/src/api/authentication/exchange_token.ts index 20edc326f23..751e51c4c2c 100644 --- a/packages/auth/src/api/authentication/exchange_token.ts +++ b/packages/auth/src/api/authentication/exchange_token.ts @@ -35,7 +35,10 @@ export async function exchangeToken( auth: Auth, request: ExchangeTokenRequest ): Promise { - return _performRegionalApiRequest( + return _performRegionalApiRequest< + ExchangeTokenRequest, + ExchangeTokenResponse + >( auth, HttpMethod.POST, RegionalEndpoint.EXCHANGE_TOKEN,