diff --git a/src/__tests__/createUser.test.ts b/src/__tests__/createUser.test.ts index 28fe8496..a9b8ab02 100644 --- a/src/__tests__/createUser.test.ts +++ b/src/__tests__/createUser.test.ts @@ -1,4 +1,6 @@ import { signOut } from 'firebase/auth' +import { setConfig } from 'src/config' +import createMockConfig from 'src/testHelpers/createMockConfig' import { createMockFirebaseUserClientSDK, createMockFirebaseUserAdminSDK, @@ -8,6 +10,8 @@ import { jest.mock('firebase/auth') jest.mock('firebase/app') +const mockSetConfig = jest.mocked(setConfig) + afterEach(() => { jest.clearAllMocks() }) @@ -117,6 +121,9 @@ describe('createUser: basic tests', () => { describe('createUser: firebaseUserClientSDK', () => { it('returns the expected data', () => { expect.assertions(1) + mockSetConfig({ + ...createMockConfig(), + }) const createUser = require('src/createUser').default const firebaseUserJSSDK = createMockFirebaseUserClientSDK() expect(createUser({ firebaseUserClientSDK: firebaseUserJSSDK })).toEqual({ @@ -138,6 +145,9 @@ describe('createUser: firebaseUserClientSDK', () => { it('returns the expected data when custom claims are included', () => { expect.assertions(1) + mockSetConfig({ + ...createMockConfig(), + }) const createUser = require('src/createUser').default const customClaims = { foo: 'bar', @@ -170,6 +180,9 @@ describe('createUser: firebaseUserClientSDK', () => { it('does not throw when custom claims are defined but the client user is not defined', () => { expect.assertions(1) + mockSetConfig({ + ...createMockConfig(), + }) const createUser = require('src/createUser').default expect(() => { createUser({ @@ -186,6 +199,9 @@ describe('createUser: firebaseUserClientSDK', () => { it('returns the expected value from getIdToken', async () => { expect.assertions(1) + mockSetConfig({ + ...createMockConfig(), + }) const createUser = require('src/createUser').default const user = createUser({ firebaseUserClientSDK: createMockFirebaseUserClientSDK(), @@ -196,6 +212,9 @@ describe('createUser: firebaseUserClientSDK', () => { it('returns the expected value from serialize', async () => { expect.assertions(1) + mockSetConfig({ + ...createMockConfig(), + }) const createUser = require('src/createUser').default const user = createUser({ firebaseUserClientSDK: createMockFirebaseUserClientSDK(), @@ -219,6 +238,9 @@ describe('createUser: firebaseUserClientSDK', () => { it("calls Firebase's signOut method when we call user.signOut", async () => { expect.assertions(1) + mockSetConfig({ + ...createMockConfig(), + }) const createUser = require('src/createUser').default const user = createUser({ firebaseUserClientSDK: createMockFirebaseUserClientSDK(), @@ -521,6 +543,9 @@ describe('createUser: serializedUser', () => { it("does not call Firebase's signOut method when we call user.signOut (it should be a noop)", async () => { expect.assertions(1) + mockSetConfig({ + ...createMockConfig(), + }) const createUser = require('src/createUser').default const user = createUser({ serializedUser: createMockSerializedUser(), diff --git a/src/__tests__/initFirebaseClientSDK.test.ts b/src/__tests__/initFirebaseClientSDK.test.ts index cfae6104..bfd8e488 100644 --- a/src/__tests__/initFirebaseClientSDK.test.ts +++ b/src/__tests__/initFirebaseClientSDK.test.ts @@ -30,12 +30,15 @@ describe('initFirebaseClientSDK', () => { expect.assertions(1) const initFirebaseClientSDK = require('src/initFirebaseClientSDK').default initFirebaseClientSDK() - expect(mockInitializeApp).toHaveBeenCalledWith({ - apiKey: 'fakeAPIKey123', - authDomain: 'my-example-app.firebaseapp.com', - databaseURL: 'https://my-example-app.firebaseio.com', - projectId: 'my-example-app-id', - }) + expect(mockInitializeApp).toHaveBeenCalledWith( + { + apiKey: 'fakeAPIKey123', + authDomain: 'my-example-app.firebaseapp.com', + databaseURL: 'https://my-example-app.firebaseio.com', + projectId: 'my-example-app-id', + }, + 'example-app-name' + ) }) it('does not call firebase.initializeApp if Firebase already has an initialized app', () => { diff --git a/src/__tests__/redirects.test.ts b/src/__tests__/redirects.test.ts index d9854c87..2b423f99 100644 --- a/src/__tests__/redirects.test.ts +++ b/src/__tests__/redirects.test.ts @@ -3,7 +3,7 @@ import type { ParsedUrlQuery } from 'querystring' import { getLoginRedirectInfo, getAppRedirectInfo } from 'src/redirects' import getMockConfig from 'src/testHelpers/createMockConfig' import { setConfig } from 'src/config' -import { User } from 'src/createUser' +import { User } from 'src/sharedTypes' import { RedirectInput } from 'src/redirectTypes' describe('redirects', () => { diff --git a/src/__tests__/withUser.test.tsx b/src/__tests__/withUser.test.tsx index 9cfb66bd..9eef87d5 100644 --- a/src/__tests__/withUser.test.tsx +++ b/src/__tests__/withUser.test.tsx @@ -8,7 +8,8 @@ import { createMockFirebaseUserClientSDK, } from 'src/testHelpers/userInputs' import useUser from 'src/useUser' -import createUser, { User } from 'src/createUser' +import createUser from 'src/createUser' +import { User } from 'src/sharedTypes' import useFirebaseUser from 'src/useFirebaseUser' import { AuthAction } from 'src/AuthAction' import logDebug from 'src/logDebug' diff --git a/src/configTypes.ts b/src/configTypes.ts index f36a3307..4d668fc6 100644 --- a/src/configTypes.ts +++ b/src/configTypes.ts @@ -1,6 +1,6 @@ import Cookies from 'cookies' import { PageURL } from './redirectTypes' -import { User } from './createUser' +import { User } from './sharedTypes' import { Spread } from './Spread' type OnErrorHandler = (error: Error) => void @@ -90,6 +90,7 @@ export interface ConfigInput { // "G-MEASUREMENT_ID" measurementId?: string } + firebaseClientAppName?: string tenantId?: string cookies: Omit & { // The base name for the auth cookies. diff --git a/src/createUser.ts b/src/createUser.ts index 4e57d700..9efa8d9c 100644 --- a/src/createUser.ts +++ b/src/createUser.ts @@ -3,6 +3,8 @@ import { User as FirebaseUser } from 'firebase/auth' import { DecodedIdToken } from 'firebase-admin/auth' import isClientSide from 'src/isClientSide' import { Claims, filterStandardClaims } from 'src/claims' +import { User } from './sharedTypes' +import { getConfig } from './config' interface UserDeserialized { id?: string @@ -30,22 +32,6 @@ interface CreateUserInput { type getIdToken = (forceRefresh?: boolean) => Promise -export interface User { - id: string | null - email: string | null - emailVerified: boolean - phoneNumber: string | null - displayName: string | null - photoURL: string | null - claims: Record - tenantId: string | null - getIdToken: (forceRefresh?: boolean) => Promise - clientInitialized: boolean - firebaseUser: FirebaseUser | null - signOut: () => Promise - serialize: (a?: { includeToken?: boolean }) => string -} - /** * Take a representation of a Firebase user from a maximum of one of: * the Firebase JS SDK, Firebase admin SDK, or serialized User instance. @@ -119,8 +105,9 @@ const createUser = ({ const { getApp } = require('firebase/app') // eslint-disable-next-line global-require, @typescript-eslint/no-var-requires const { getAuth, signOut } = require('firebase/auth') + const { firebaseClientAppName } = getConfig() - signOutFunc = async () => signOut(getAuth(getApp())) + signOutFunc = async () => signOut(getAuth(getApp(firebaseClientAppName))) } /** diff --git a/src/firebaseAdmin.ts b/src/firebaseAdmin.ts index 19879c1b..95fa226b 100644 --- a/src/firebaseAdmin.ts +++ b/src/firebaseAdmin.ts @@ -1,6 +1,7 @@ import { getAuth as getAdminAuth } from 'firebase-admin/auth' import initFirebaseAdminSDK from 'src/initFirebaseAdminSDK' -import createUser, { User } from 'src/createUser' +import createUser from 'src/createUser' +import { User } from 'src/sharedTypes' import { getConfig } from 'src/config' import logDebug from 'src/logDebug' import { FirebaseError as FirebaseErrorType } from 'firebase-admin/app' diff --git a/src/getUserFromCookies.ts b/src/getUserFromCookies.ts index 5e2df2e8..9338c8a7 100644 --- a/src/getUserFromCookies.ts +++ b/src/getUserFromCookies.ts @@ -1,4 +1,5 @@ -import createUser, { User } from 'src/createUser' +import createUser from 'src/createUser' +import { User } from 'src/sharedTypes' import { getCookie } from 'src/cookies' import { verifyIdToken } from 'src/firebaseAdmin' import { diff --git a/src/initFirebaseClientSDK.ts b/src/initFirebaseClientSDK.ts index 22dc7372..96c09215 100644 --- a/src/initFirebaseClientSDK.ts +++ b/src/initFirebaseClientSDK.ts @@ -4,8 +4,12 @@ import { getConfig } from 'src/config' import logDebug from 'src/logDebug' export default function initFirebaseClientSDK() { - const { firebaseClientInitConfig, firebaseAuthEmulatorHost, tenantId } = - getConfig() + const { + firebaseClientInitConfig, + firebaseAuthEmulatorHost, + tenantId, + firebaseClientAppName, + } = getConfig() if (!getApps().length) { if (!firebaseClientInitConfig) { throw new Error( @@ -13,7 +17,7 @@ export default function initFirebaseClientSDK() { ) } - initializeApp(firebaseClientInitConfig) + initializeApp(firebaseClientInitConfig, firebaseClientAppName) if (tenantId) { getAuth().tenantId = tenantId } @@ -25,6 +29,9 @@ export default function initFirebaseClientSDK() { } // If the user has provided the firebaseAuthEmulatorHost address, set the emulator if (firebaseAuthEmulatorHost) { - connectAuthEmulator(getAuth(getApp()), `http://${firebaseAuthEmulatorHost}`) + connectAuthEmulator( + getAuth(getApp(firebaseClientAppName)), + `http://${firebaseAuthEmulatorHost}` + ) } } diff --git a/src/redirectTypes.ts b/src/redirectTypes.ts index 000e9d2d..3480cf83 100644 --- a/src/redirectTypes.ts +++ b/src/redirectTypes.ts @@ -1,6 +1,6 @@ import type { GetServerSidePropsContext, Redirect } from 'next' import type { ParsedUrlQuery } from 'querystring' -import { User } from './createUser' +import { User } from './sharedTypes' export type URLResolveFunction = (obj: { ctx?: GetServerSidePropsContext diff --git a/src/redirects.ts b/src/redirects.ts index eeae7790..1ee14007 100644 --- a/src/redirects.ts +++ b/src/redirects.ts @@ -1,6 +1,6 @@ import type { GetServerSidePropsContext } from 'next' -import { User } from 'src/createUser' +import { User } from 'src/sharedTypes' import { getConfig } from 'src/config' import { PageURL, diff --git a/src/setAuthCookies.ts b/src/setAuthCookies.ts index 14a79e0e..b9b136f2 100644 --- a/src/setAuthCookies.ts +++ b/src/setAuthCookies.ts @@ -3,7 +3,8 @@ import { setCookie } from 'src/cookies' import { getUserCookieName, getUserTokensCookieName } from 'src/authCookies' import { getConfig } from 'src/config' import logDebug from 'src/logDebug' -import createUser, { User } from 'src/createUser' +import createUser from 'src/createUser' +import { User } from 'src/sharedTypes' import { NextApiRequest, NextApiResponse } from 'next' export type SetAuthCookies = ( diff --git a/src/sharedTypes.ts b/src/sharedTypes.ts new file mode 100644 index 00000000..0d8346a5 --- /dev/null +++ b/src/sharedTypes.ts @@ -0,0 +1,17 @@ +import { User as FirebaseUser } from 'firebase/auth' + +export interface User { + id: string | null + email: string | null + emailVerified: boolean + phoneNumber: string | null + displayName: string | null + photoURL: string | null + claims: Record + tenantId: string | null + getIdToken: (forceRefresh?: boolean) => Promise + clientInitialized: boolean + firebaseUser: FirebaseUser | null + signOut: () => Promise + serialize: (a?: { includeToken?: boolean }) => string +} diff --git a/src/testHelpers/createMockConfig.ts b/src/testHelpers/createMockConfig.ts index ed51e62c..f54923e5 100644 --- a/src/testHelpers/createMockConfig.ts +++ b/src/testHelpers/createMockConfig.ts @@ -29,6 +29,7 @@ const createMockConfig = ({ clientSide }: { clientSide?: boolean } = {}) => { databaseURL: 'https://my-example-app.firebaseio.com', projectId: 'my-example-app-id', }, + firebaseClientAppName: 'example-app-name', cookies: { name: 'someExample', keys: useClientSideConfig ? [] : ['abc', 'def'], diff --git a/src/useFirebaseUser.ts b/src/useFirebaseUser.ts index e5bc20f5..93f9c02b 100644 --- a/src/useFirebaseUser.ts +++ b/src/useFirebaseUser.ts @@ -7,7 +7,8 @@ import { onIdTokenChanged, } from 'firebase/auth' import { getConfig } from 'src/config' -import createUser, { User } from 'src/createUser' +import createUser from 'src/createUser' +import { User } from 'src/sharedTypes' import { Claims, filterStandardClaims } from 'src/claims' import logDebug from 'src/logDebug' @@ -175,7 +176,10 @@ const useFirebaseUser = () => { } // https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onidtokenchanged - const unsubscribe = onIdTokenChanged(getAuth(getApp()), onIdTokenChange) + + const { firebaseClientAppName } = getConfig() + const app = getApp(firebaseClientAppName) + const unsubscribe = onIdTokenChanged(getAuth(app), onIdTokenChange) return () => { unsubscribe() isCancelled = true diff --git a/src/useUser.tsx b/src/useUser.tsx index 12b4734d..1d683312 100644 --- a/src/useUser.tsx +++ b/src/useUser.tsx @@ -1,5 +1,5 @@ import { createContext, useContext } from 'react' -import { User } from './createUser' +import { User } from './sharedTypes' type UserContext = | (User & { diff --git a/src/withUserTokenSSR.ts b/src/withUserTokenSSR.ts index 7b502996..80c9dd35 100644 --- a/src/withUserTokenSSR.ts +++ b/src/withUserTokenSSR.ts @@ -10,7 +10,7 @@ import getUserFromCookies from 'src/getUserFromCookies' import { AuthAction } from 'src/AuthAction' import { getLoginRedirectInfo, getAppRedirectInfo } from 'src/redirects' import logDebug from 'src/logDebug' -import { User } from './createUser' +import { User } from './sharedTypes' import { PageURL } from './redirectTypes' export interface WithUserSSROptions {