Skip to content

Commit

Permalink
tenant support to v1.x (#647)
Browse files Browse the repository at this point in the history
* Debug release action

* 0.14.0-alpha.0

* Revert "0.14.0-alpha.0"

This reverts commit 1e04c95.

* Remove --dry-run from release action

* Display the Firebase version on the demo app

* Update README.md

* Update issue templates

* feat: forceRefresh on getIdToken

* feat: adding description about forceRefresh

* feat: adding argument type to getIdToken

* Update createAuthUser.js

* 0.13.4-alpha.0

* 0.13.4

* Upgrade some dependencies (#325)

* Upgrade some deps

* Upgrade caniuse

* Upgrade Prettier

* Downgrade eslint to satisfy peerdeps

* Minor upgrades for Next and Firebase deps

* Upgrade firebase-admin

* Upgrade firebase-admin in demo

* Minor upgrade demo deps

* Upgrade NFA version in demo

* Upgrade more dependencies

* Upgrade more demo dependencies

* Revert "Upgrade more demo dependencies"

This reverts commit 7da3e58.

* Revert "Minor upgrade demo deps"

This reverts commit 50f928e.

* Minor upgrade Firebase

* Pin typescript version (typing error with 4.4.4) and minor upgrade other types

* Minor bump a few demo deps

* Upgrade more demo deps

* Upgrade some deps

* Remove unused Codecov dependency

* Support Next 12 and Firebase Admin 10 (#328)

* Use Next 12

* Allow latest versions of Next and firebase-admin

* 0.13.5-alpha.0

* Update demo to use Next 12  (#330)

* Use Next 12

* Allow latest versions of Next and firebase-admin

* Upgrade Next to v12

* Update demo

* Update README.md

* Update README.md

* Change example app cookies to use SameSite=lax (#354)

* 0.13.5

* feat: add support for application default credentials (#348)

* feat: fallback to applicationDefault credentials

Co-Authored-By: Jesse Anderson <jeryanders@gmail.com>

* chore: add test for firebaseAdminDefaultCredential

* chore: update README with firebaseAdminDefaultCredential

Co-Authored-By: Jesse Anderson <jeryanders@gmail.com>

* chore: cleanup wording in README comments

* fix: updates based on comments

* chore: update error message in test

Co-authored-by: Jesse Anderson <jeryanders@gmail.com>

* Update README.md

* Upgrade dependencies on v0.x (#356)

* Upgrade most deps

* Upgrade ESLint and Prettier and lint fix

* Remove unneeded jsdom dep

* Upgrade most example app deps

* Upgrade example app lockfile deps

* Upgrade lockfile deps

* Fix peer dependency range syntax for firebase-admin (#358)

* Handle additional token errors in verifyIdToken (#361) (#365)

* fix: check for 'auth/argument-error' when verifying token

* feat: upgrade firebase and firebase-admin

* feat(#174): handle additional errors from `verifyIdToken`

* test(#174): add tests coverage for new errors in `verifyIdToken`

* feat: upgrade dependencies that have non breaking changes

* feat: implement pr feedback

* chore: upgrade dependencies

* Rebuild lockfile

* Include error if empty refreshToken

* Add TODO

Co-authored-by: Zino Hofmann <zino@hofmann.amsterdam>

Co-authored-by: Zino Hofmann <zino@hofmann.amsterdam>

* Remove thrown errors from token refresh & verification logic (#368)

* Add broken tests

* Don't throw on token errors

* Add assertion checks to tests

* Add/modify comments in config validation

* Move tests into describe block

* Add error callbacks to config

* Call error callbacks when we fail to refresh or verify the user's ID token

* Add new config properties to types

* Await error callback functions in case they need to perform something async

* Lint fixes

* Add tests

* Update README.md

* Fix typo in README (#374)

* Cherry pick v1.x #369 (#375)

Co-authored-by: Faris Abusada <abusada@users.noreply.github.com>

* Allow easy error handling for login/logout requests (#376)

* Add error catching to default token changed handler

* Add new config properties

* Update README.md

* Update README.md

* Run Prettier on README (#381)

* 0.14.0-alpha.o

* Update README.md

* 0.14.0-alpha.1

* Update v0.x example (#382)

* Update documentation (#387)

* Update docs on private key formatting and Vercel environment variables (#385)

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Add note about not using API routes in getServerSideProps (#386)

* 0.14.0

* Added troubleshooting step to README (#398)

* Update README.md

* feat: add ability to define to redirect to app with different base path (#352)

* feat: add generalized redirect AuthAction

* test: add tests for csr and ssr withAuthUser

* fix: made error message more focused on a given auth state

* fix: removed new AuthAction and address issue 187 with new solution

* test: add main tests for new schema on appPageURL and authPageURL

* refactor: move destination logic into common function

* refactor: add redirects

* refactor: error messaging around redirects

* fix: router and window location

* test: add test coverage for new supported data type

* docs: rework docs

* fix: error message for authPageURL

* fix: bug in ssr component and slightly later url schema

* docs: change schema property

* fix: allow basePath on SSR to be passed based on findings

* chore: make naming consistent between csr / ssr

* fix: rework based on feedback

* refactor: bring config access into redirect module

* style: spacing and formatting

* docs: update readme and types

* refactor: simplify object name

* fix: update typescript

* tests: fix tests causing coverage issues

* fix: rework from feedback

* fix: implement feedback

* test: add additional test

* test: adjust test name

* Update documentation for redirects (#400)

* Add PageURL type to README

* Typo fix

* Link to PageURL type in docs

* Run Prettier on README

* Fix incorrect documentation args

* Link to PageURL type from example

* Tweak README

* Fix typo

* Add info about ctx

* Remove redundant info

* Tweak code comments

* 0.14.1-alpha.0

* Update example app (#402)

* 0.14.1

* added onLogoutRequestError and onLoginRequestError to InitConfig interface (#427)

* feat: add tenant integration

* Update link to documentation

* 0.14.2

* Bugfix: don't error on unset Firebase admin config values (#436)

* Identify bug

* When debug logging, handle unset Firebase config values

* Lint fix

* 0.14.3-alpha.0

* fix: Add useFirebaseAdminDefaultCredential type definition (#451)

* Fix README typos, grammar (#448)

* Add useFirebaseAdminDefaultCredential type definition

* Fix typos, grammar, and clarify Google default credentials usage

* docs: Fix grammar, remove type addition from PR

* 0.14.3-alpha.1

* 0.14.3

* Upgrade NFA version in demo (#455)

* Upgrade NFA version in demo

* Update min version

* v0.x: Add support for React 18 (#472)

* Add support for React 18

* Upgrade some testing libraries

* v0.x: upgrade dependencies (#477)

* Upgrade most deps

* Upgrade additional deps

* 0.14.4-alpha.0

* v0.x: Update example app (React 18, other dependencies) (#471)

* Update example to use React 18

* Add latest NFA

* Upgrade other deps in example app

* Ignore type error

* Use supported version of react-firebaseui

* Upgrade additional example app dependencies (#479)

* fix typo. add missing "b" to README.md (#485)

* Support firebase-admin v11 peer dependency (#504)

* Upgrade dependencies [v0.x] (#505)

* Upgrade some deps

* Upgrade Prettier

* Upgrade dependencies

* Upgrade firebase-admin and copy-webpack-plugin

* Upgrade example deps [v0.x] (#507)

* Upgrade deps

* Upgrade deps

* Use compatible react-firebaseui

* 0.14.4-alpha.1

* Bump NFA in package.json

* Upgrade NFA in example (#508)

* 0.14.4

* Use NFA 0.14.4 in example app (#509)

* Add info about NextAuth.js to README [v1.x]

* Update README.md

* v0.x: Update bug issue template (#542)

* v0.x: allow Next v13 peer dependency (#588)

* 0.15.0

* Update README.md

* docs: adds missing import to withAuthUserTokenSSR example

* fix: make sure Firebase admin is initialized in getUserFromCookies

* docs: tenantId commented by default

* fix: correct attribute name to tenantId in deserializedUser

* fix: extract tenantId from firebaseClientInitConfig

* tests: add tenantId tests for createAuthUser. adds tests for tenantId in initFirebaseClientSDK.

* merge fixes

* merge fixes

* merge fixes

* merge fixes

* fix: firebaseAdmin test. use getAuth

* remove extra changes from docs

* fix doc formatting

* fix minor issues

* empy line

* fix: change auth instance

* fix: remove admin import

* fix: move tenantId outside firebaseClientInitConfig. Fix typos

* Update src/__tests__/firebaseAdmin.test.ts

---------

Co-authored-by: Kevin Jennison <kevin.jennison1@gmail.com>
Co-authored-by: Guilherme <guiilherme.bayer@gmail.com>
Co-authored-by: Scott Prue <prescottprue@users.noreply.github.com>
Co-authored-by: Jesse Anderson <jeryanders@gmail.com>
Co-authored-by: Zino Hofmann <zino@hofmann.amsterdam>
Co-authored-by: Alexander Cai <alexandercai@outlook.com>
Co-authored-by: Faris Abusada <abusada@users.noreply.github.com>
Co-authored-by: Vinny <vpaladino778@gmail.com>
Co-authored-by: Jesse Anderson <jesse.anderson@sideinc.com>
Co-authored-by: camilo-mujica <84539709+camilo-mujica@users.noreply.github.com>
Co-authored-by: Hegar Garcia <hegargarcia@gmail.com>
Co-authored-by: Hung Vu <hunghvu2017@gmail.com>
Co-authored-by: nori-k <norikatsu.kamiya@gmail.com>
  • Loading branch information
14 people authored Jul 8, 2023
1 parent ee6443e commit 47e627f
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 14 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ const initAuth = () => {
databaseURL: 'https://my-example-app.firebaseio.com',
projectId: 'my-example-app-id',
},
// tenantId: 'example-tenant-id', // Optional, only necessary in multi-tenant configuration
cookies: {
name: 'ExampleApp', // required
// Keys are required unless you set `signed` to `false`.
Expand Down
21 changes: 21 additions & 0 deletions __mocks__/firebase-admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const firebaseAdminMock = jest.createMockFromModule('firebase-admin')

const mockTenantValue = {
createCustomToken: jest.fn(() => Promise.resolve(null)),
verifyIdToken: jest.fn(() => Promise.resolve(null)),
}

const mockAuthForTenant = jest.fn(() => mockTenantValue)

const mockAuthValue = {
...mockTenantValue,
tenantManager: () => ({
authForTenant: mockAuthForTenant,
}),
}

firebaseAdminMock.auth = jest.fn(() => mockAuthValue)

firebaseAdminMock.apps = []

module.exports = firebaseAdminMock
20 changes: 16 additions & 4 deletions __mocks__/firebase-admin/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@ export {}

const { Auth } = jest.requireActual('firebase-admin/auth')

const firebaseAdminAuthMock: jest.Mocked<typeof Auth> =
jest.createMockFromModule('firebase-admin/auth')
const firebaseAdminAuth: jest.Mocked<typeof Auth> = jest.createMockFromModule(
'firebase-admin/auth'
)

const mockTenantValue = {
createCustomToken: jest.fn(() => Promise.resolve(null)),
verifyIdToken: jest.fn(() => Promise.resolve(null)),
getUser: jest.fn(() => Promise.resolve(null)) as jest.Mock,
}

const mockAuthForTenant = jest.fn(() => mockTenantValue) as jest.Mock

const auth = {
createCustomToken: jest.fn(async () => null) as jest.Mock,
verifyIdToken: jest.fn(async () => null) as jest.Mock,
getUser: jest.fn(() => Promise.resolve(null)) as jest.Mock,
tenantManager: jest.fn(() => ({
authForTenant: mockAuthForTenant,
})) as jest.Mock,
}

firebaseAdminAuthMock.getAuth = jest.fn(() => auth)
firebaseAdminAuth.getAuth = jest.fn(() => auth)

module.exports = firebaseAdminAuthMock
module.exports = firebaseAdminAuth
92 changes: 92 additions & 0 deletions src/__tests__/createAuthUser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe('createAuthUser: basic tests', () => {
clientInitialized: false,
email: null,
emailVerified: false,
tenantId: null,
phoneNumber: null,
displayName: null,
photoURL: null,
Expand Down Expand Up @@ -125,6 +126,7 @@ describe('createAuthUser: firebaseUserClientSDK', () => {
email: 'abc@example.com',
emailVerified: true,
phoneNumber: '+1800-123-4567',
tenantId: null,
displayName: 'Abc Cdf',
photoURL: 'https://abc.googleusercontent.com/cdf/profile_photo.png',
clientInitialized: false,
Expand Down Expand Up @@ -156,6 +158,7 @@ describe('createAuthUser: firebaseUserClientSDK', () => {
email: 'abc@example.com',
emailVerified: true,
phoneNumber: '+1800-123-4567',
tenantId: null,
displayName: 'Abc Cdf',
photoURL: 'https://abc.googleusercontent.com/cdf/profile_photo.png',
clientInitialized: false,
Expand Down Expand Up @@ -206,6 +209,7 @@ describe('createAuthUser: firebaseUserClientSDK', () => {
claims: {},
email: 'abc@example.com',
emailVerified: true,
tenantId: null,
phoneNumber: '+1800-123-4567',
displayName: 'Abc Cdf',
photoURL: 'https://abc.googleusercontent.com/cdf/profile_photo.png',
Expand Down Expand Up @@ -247,6 +251,7 @@ describe('createAuthUser: firebaseUserAdminSDK', () => {
email: 'def@example.com',
emailVerified: true,
phoneNumber: '+1800-234-5678',
tenantId: null,
displayName: 'Def Ghi',
photoURL: 'https://def.googleusercontent.com/ghi/profile_photo.png',
clientInitialized: false,
Expand All @@ -271,6 +276,7 @@ describe('createAuthUser: firebaseUserAdminSDK', () => {
email: 'def@example.com',
emailVerified: true,
phoneNumber: '+1800-234-5678',
tenantId: null,
displayName: 'Def Ghi',
photoURL: 'https://def.googleusercontent.com/ghi/profile_photo.png',
clientInitialized: false,
Expand Down Expand Up @@ -332,6 +338,7 @@ describe('createAuthUser: firebaseUserAdminSDK', () => {
claims: {},
email: 'def@example.com',
emailVerified: true,
tenantId: null,
phoneNumber: '+1800-234-5678',
displayName: 'Def Ghi',
photoURL: 'https://def.googleusercontent.com/ghi/profile_photo.png',
Expand All @@ -355,6 +362,7 @@ describe('createAuthUser: firebaseUserAdminSDK', () => {
claims: {},
email: 'def@example.com',
emailVerified: true,
tenantId: null,
phoneNumber: '+1800-234-5678',
displayName: 'Def Ghi',
photoURL: 'https://def.googleusercontent.com/ghi/profile_photo.png',
Expand Down Expand Up @@ -387,6 +395,7 @@ describe('createAuthUser: firebaseUserAdminSDK', () => {
claims: customClaims,
email: 'def@example.com',
emailVerified: true,
tenantId: null,
phoneNumber: '+1800-234-5678',
displayName: 'Def Ghi',
photoURL: 'https://def.googleusercontent.com/ghi/profile_photo.png',
Expand All @@ -410,6 +419,7 @@ describe('createAuthUser: firebaseUserAdminSDK', () => {
claims: {},
email: 'def@example.com',
emailVerified: true,
tenantId: null,
phoneNumber: '+1800-234-5678',
displayName: 'Def Ghi',
photoURL: 'https://def.googleusercontent.com/ghi/profile_photo.png',
Expand Down Expand Up @@ -442,6 +452,7 @@ describe('createAuthUser: serializedAuthUser', () => {
email: 'ghi@example.com',
emailVerified: true,
phoneNumber: '+1800-345-6789',
tenantId: null,
displayName: 'Ghi Jkl',
photoURL: 'https://ghi.googleusercontent.com/jkl/profile_photo.png',
clientInitialized: false,
Expand Down Expand Up @@ -470,6 +481,7 @@ describe('createAuthUser: serializedAuthUser', () => {
email: 'ghi@example.com',
emailVerified: true,
phoneNumber: '+1800-345-6789',
tenantId: null,
displayName: 'Ghi Jkl',
photoURL: 'https://ghi.googleusercontent.com/jkl/profile_photo.png',
clientInitialized: false,
Expand Down Expand Up @@ -520,4 +532,84 @@ describe('createAuthUser: serializedAuthUser', () => {
await AuthUser.signOut()
expect(signOut).not.toHaveBeenCalled()
})

it('returns expected data when tenantId set in firebaseUserClientSDK', () => {
expect.assertions(1)
const createAuthUser = require('src/createAuthUser').default
const firebaseUserJSSDK = createMockFirebaseUserClientSDK({
tenantId: 'some-tenant-id',
})
expect(
createAuthUser({
firebaseUserClientSDK: firebaseUserJSSDK,
})
).toEqual({
id: 'abc-123',
email: 'abc@example.com',
emailVerified: true,
phoneNumber: '+1800-123-4567',
displayName: 'Abc Cdf',
photoURL: 'https://abc.googleusercontent.com/cdf/profile_photo.png',
clientInitialized: false,
getIdToken: expect.any(Function),
firebaseUser: firebaseUserJSSDK,
signOut: expect.any(Function),
serialize: expect.any(Function),
claims: {},
tenantId: 'some-tenant-id',
})
})

it('returns expected data when tenantId set in firebaseUserAdminSDK', () => {
expect.assertions(1)
const createAuthUser = require('src/createAuthUser').default
const firebaseUserAdminSDK = createMockFirebaseUserAdminSDK({
tenant: 'some-tenant-id',
})
expect(
createAuthUser({
firebaseUserAdminSDK,
})
).toEqual({
id: 'def-456',
email: 'def@example.com',
emailVerified: true,
phoneNumber: '+1800-234-5678',
displayName: 'Def Ghi',
photoURL: 'https://def.googleusercontent.com/ghi/profile_photo.png',
clientInitialized: false,
getIdToken: expect.any(Function),
firebaseUser: null,
signOut: expect.any(Function),
serialize: expect.any(Function),
claims: {},
tenantId: 'some-tenant-id',
})
})

it('returns the expected data when tenantId in serializedAuthUser', () => {
expect.assertions(1)
const createAuthUser = require('src/createAuthUser').default
expect(
createAuthUser({
serializedAuthUser: createMockSerializedAuthUser({
tenantId: 'some-tenant-id',
}),
})
).toEqual({
id: 'ghi-789',
email: 'ghi@example.com',
emailVerified: true,
phoneNumber: '+1800-345-6789',
displayName: 'Ghi Jkl',
photoURL: 'https://ghi.googleusercontent.com/jkl/profile_photo.png',
clientInitialized: false,
getIdToken: expect.any(Function),
firebaseUser: null,
signOut: expect.any(Function),
serialize: expect.any(Function),
claims: {},
tenantId: 'some-tenant-id',
})
})
})
38 changes: 38 additions & 0 deletions src/__tests__/firebaseAdmin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1283,5 +1283,43 @@ describe('getCustomIdAndRefreshTokens', () => {
'A `fetch` global is required when using next-firebase-auth. See documentation on setting up a `fetch` polyfill.'
)
})

it('changes auth instance if there is a tenant', async () => {
const { getCustomIdAndRefreshTokens } = require('src/firebaseAdmin')

const mockTenant = 'test-tenant'
const mockConfig = createMockConfig()
setConfig({
...mockConfig,
firebaseClientInitConfig: {
...mockConfig.firebaseClientInitConfig,
apiKey: 'some-key',
},
tenantId: mockTenant,
})

const mockUserRecord = createMockFirebaseUserRecord()
const mockFirebaseUser = createMockFirebaseUserAdminSDK({
tenant: mockTenant,
})

const firebaseAdminAuth = mockGetAuth()
const tenantAuth = firebaseAdminAuth
.tenantManager()
.authForTenant(mockTenant)

tenantAuth.verifyIdToken.mockResolvedValue(mockFirebaseUser)
tenantAuth.createCustomToken.mockResolvedValue('my-custom-token')
tenantAuth.getUser.mockResolvedValue(mockUserRecord)

await getCustomIdAndRefreshTokens('some-token')
expect(
firebaseAdminAuth.tenantManager().authForTenant
).toHaveBeenCalledWith(mockTenant)
expect(tenantAuth.createCustomToken).toHaveBeenCalledWith(
mockFirebaseUser.uid,
mockUserRecord.customClaims
)
})
})
/* END: getCustomIdAndRefreshTokens tests */
31 changes: 31 additions & 0 deletions src/__tests__/initFirebaseClientSDK.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,35 @@ describe('initFirebaseClientSDK', () => {
'[init] Did not initialize the Firebase JS SDK because an app already exists.'
)
})

it('sets the tenantId if config.tenantId is set', () => {
expect.assertions(1)
const mockConfig = createMockConfig()
setConfig({
...mockConfig,
firebaseClientInitConfig: {
...mockConfig.firebaseClientInitConfig,
},
tenantId: 'my-tenant-id',
})

const initFirebaseClientSDK = require('src/initFirebaseClientSDK').default

// Mocking the getter and setter for firebase.auth().tenantId
const mockAuth = {
mockTenantId: 'test',
get tenantId() {
return this.mockTenantId
},
set tenantId(value) {
this.mockTenantId = value
},
}

mockGetApps.mockReturnValue([])
mockGetAuth.mockReturnValue(mockAuth)

initFirebaseClientSDK()
expect(getAuth().tenantId).toEqual('my-tenant-id')
})
})
1 change: 1 addition & 0 deletions src/configTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export interface ConfigInput {
// "G-MEASUREMENT_ID"
measurementId?: string
}
tenantId?: string
cookies: Omit<Cookies.Option & Cookies.SetOption, 'sameSite'> & {
// The base name for the auth cookies.
name: string
Expand Down
Loading

0 comments on commit 47e627f

Please sign in to comment.