Skip to content

Commit

Permalink
Let user specify the firebase app name (#716)
Browse files Browse the repository at this point in the history
* Take over changes from previous PR

* Fix dependency cycle

* Fix other imports

* Fix all other remaining imports

* Fix first prettier errors

* Remove debug commands

* Remove unnecessary try catch

* Add example app name

* Remove config mention

* Bring back firebase client app name

* Add mock configs

* Update configTypes.ts

Co-authored-by: Kevin Jennison <[email protected]>

---------

Co-authored-by: Kevin Jennison <[email protected]>
  • Loading branch information
MvRemmerden and kmjennison authored Jul 1, 2024
1 parent d51bf07 commit ebc2b2b
Show file tree
Hide file tree
Showing 17 changed files with 88 additions and 39 deletions.
25 changes: 25 additions & 0 deletions src/__tests__/createUser.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { signOut } from 'firebase/auth'
import { setConfig } from 'src/config'
import createMockConfig from 'src/testHelpers/createMockConfig'
import {
createMockFirebaseUserClientSDK,
createMockFirebaseUserAdminSDK,
Expand All @@ -8,6 +10,8 @@ import {
jest.mock('firebase/auth')
jest.mock('firebase/app')

const mockSetConfig = jest.mocked(setConfig)

afterEach(() => {
jest.clearAllMocks()
})
Expand Down Expand Up @@ -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({
Expand All @@ -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',
Expand Down Expand Up @@ -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({
Expand All @@ -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(),
Expand All @@ -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(),
Expand All @@ -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(),
Expand Down Expand Up @@ -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(),
Expand Down
15 changes: 9 additions & 6 deletions src/__tests__/initFirebaseClientSDK.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/__tests__/redirects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
3 changes: 2 additions & 1 deletion src/__tests__/withUser.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
3 changes: 2 additions & 1 deletion src/configTypes.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -90,6 +90,7 @@ export interface ConfigInput {
// "G-MEASUREMENT_ID"
measurementId?: string
}
firebaseClientAppName?: string
tenantId?: string
cookies: Omit<Cookies.Option & Cookies.SetOption, 'sameSite'> & {
// The base name for the auth cookies.
Expand Down
21 changes: 4 additions & 17 deletions src/createUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -30,22 +32,6 @@ interface CreateUserInput {

type getIdToken = (forceRefresh?: boolean) => Promise<string | null>

export interface User {
id: string | null
email: string | null
emailVerified: boolean
phoneNumber: string | null
displayName: string | null
photoURL: string | null
claims: Record<string, string | boolean>
tenantId: string | null
getIdToken: (forceRefresh?: boolean) => Promise<string | null>
clientInitialized: boolean
firebaseUser: FirebaseUser | null
signOut: () => Promise<void>
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.
Expand Down Expand Up @@ -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)))
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/firebaseAdmin.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
3 changes: 2 additions & 1 deletion src/getUserFromCookies.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
15 changes: 11 additions & 4 deletions src/initFirebaseClientSDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ 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(
'If not initializing the Firebase JS SDK elsewhere, you must provide "firebaseClientInitConfig" to next-firebase-auth.'
)
}

initializeApp(firebaseClientInitConfig)
initializeApp(firebaseClientInitConfig, firebaseClientAppName)
if (tenantId) {
getAuth().tenantId = tenantId
}
Expand All @@ -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}`
)
}
}
2 changes: 1 addition & 1 deletion src/redirectTypes.ts
Original file line number Diff line number Diff line change
@@ -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<ParsedUrlQuery>
Expand Down
2 changes: 1 addition & 1 deletion src/redirects.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/setAuthCookies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = (
Expand Down
17 changes: 17 additions & 0 deletions src/sharedTypes.ts
Original file line number Diff line number Diff line change
@@ -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<string, string | boolean>
tenantId: string | null
getIdToken: (forceRefresh?: boolean) => Promise<string | null>
clientInitialized: boolean
firebaseUser: FirebaseUser | null
signOut: () => Promise<void>
serialize: (a?: { includeToken?: boolean }) => string
}
1 change: 1 addition & 0 deletions src/testHelpers/createMockConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'],
Expand Down
8 changes: 6 additions & 2 deletions src/useFirebaseUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/useUser.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { createContext, useContext } from 'react'
import { User } from './createUser'
import { User } from './sharedTypes'

type UserContext =
| (User & {
Expand Down
2 changes: 1 addition & 1 deletion src/withUserTokenSSR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit ebc2b2b

Please sign in to comment.