Skip to content

Commit 28e9409

Browse files
committed
feat(auth): allow customizing auth initialization
Close #1351
1 parent a12367e commit 28e9409

File tree

7 files changed

+134
-40
lines changed

7 files changed

+134
-40
lines changed

packages/nuxt/src/module.ts

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ export default defineNuxtModule<VueFireNuxtModuleOptions>({
7070
},
7171
auth: {
7272
enabled: isAuthEnabled,
73+
errorMap: process.env.NODE_ENV !== 'production' ? 'debug' : 'prod',
74+
persistence: ['indexedDBLocal', 'browserLocal'],
75+
popupRedirectResolver: 'browser',
7376
...(typeof _options.auth === 'object' ? _options.auth : {}),
7477
},
7578
} satisfies VueFireNuxtModuleOptionsResolved
@@ -199,23 +202,8 @@ export default defineNuxtModule<VueFireNuxtModuleOptions>({
199202
addPlugin(resolve(runtimeDir, 'auth/plugin-mint-cookie.client'))
200203
}
201204

202-
// hydrates the user if any
203-
addPlugin(resolve(runtimeDir, 'auth/plugin.client'))
204205
// loads the user on the current app
205206
addPlugin(resolve(runtimeDir, 'auth/plugin.server'))
206-
207-
addVueFireImports([
208-
// auth
209-
{ from: 'vuefire', name: 'useFirebaseAuth' },
210-
{ from: 'vuefire', name: 'useCurrentUser' },
211-
])
212-
// these are improved for nuxt to avoid the need to pass the app name
213-
addImports([
214-
{
215-
from: resolve(runtimeDir, 'auth/composables'),
216-
name: 'getCurrentUser',
217-
},
218-
])
219207
}
220208

221209
// Emulators must be enabled after the app is initialized but before some APIs like auth.signinWithCustomToken() are called
@@ -243,6 +231,31 @@ export default defineNuxtModule<VueFireNuxtModuleOptions>({
243231
}
244232
}
245233

234+
// we must initialize auth before emulators
235+
if (options.auth.enabled) {
236+
// hydrates the user if any
237+
addPluginTemplate({
238+
src: normalize(resolve(runtimeDir, 'auth/plugin.client.ejs')),
239+
options: {
240+
...options.auth,
241+
},
242+
})
243+
addPlugin(resolve(runtimeDir, 'auth/plugin-base.server'))
244+
245+
addVueFireImports([
246+
// auth
247+
{ from: 'vuefire', name: 'useFirebaseAuth' },
248+
{ from: 'vuefire', name: 'useCurrentUser' },
249+
])
250+
// these are improved for nuxt to avoid the need to pass the app name
251+
addImports([
252+
{
253+
from: resolve(runtimeDir, 'auth/composables'),
254+
name: 'getCurrentUser',
255+
},
256+
])
257+
}
258+
246259
// adds the firebase app to each application
247260
addPlugin(resolve(runtimeDir, 'app/plugin.client'))
248261
addPlugin(resolve(runtimeDir, 'app/plugin.server'))

packages/nuxt/src/module/options.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,26 @@ import type { FirebaseOptions } from 'firebase/app'
22
import type { AppOptions } from 'firebase-admin'
33
import type { NuxtVueFireAppCheckOptions } from '../runtime/app-check'
44

5+
export interface VueFireNuxtAuthDependencies {
6+
/**
7+
* Map of errors. Defaults to debug during dev and to prod during production. Should not be changed unless you know
8+
* what you are doing.
9+
*/
10+
errorMap?: 'debug' | 'prod' | false
11+
12+
/**
13+
* The popup redirect resolver. Defaults to `browser`. Can be set to `false` to disable it.
14+
*/
15+
popupRedirectResolver?: 'browser' | false
16+
17+
/**
18+
* The persistence to use. Defaults to `['indexedDBLocal', 'browserLocal']`.
19+
*/
20+
persistence?: Array<
21+
'indexedDBLocal' | 'browserLocal' | 'browserSession' | 'inMemory'
22+
>
23+
}
24+
525
export interface VueFireNuxtModuleOptions {
626
/**
727
* Should we add the `VueFireFirestoreOptionsAPI` and `VueFireRealtimeDatabaseOptionsAPI` modules?. Pass `true` to add
@@ -37,7 +57,7 @@ export interface VueFireNuxtModuleOptions {
3757
*/
3858
auth?:
3959
| boolean
40-
| {
60+
| ({
4161
/**
4262
* Adds the Authentication module to VueFire.
4363
* @defaultValue `false`
@@ -52,7 +72,7 @@ export interface VueFireNuxtModuleOptions {
5272
* in Firebase docs: [Manage Session Cookies](https://firebase.google.com/docs/auth/admin/manage-cookies).
5373
*/
5474
sessionCookie?: boolean
55-
}
75+
} & VueFireNuxtAuthDependencies)
5676

5777
/**
5878
* Controls whether to use emulators or not. Pass `false` to disable emulators. When set to `true`, emulators are
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { FirebaseApp } from 'firebase/app'
2+
import { debugErrorMap, prodErrorMap, type User } from 'firebase/auth'
3+
import { _VueFireAuthInit } from 'vuefire'
4+
import { defineNuxtPlugin } from '#imports'
5+
6+
/**
7+
* Setups VueFireAuth for the client. This version creates some listeners that shouldn't be set on server.
8+
*/
9+
export default defineNuxtPlugin((nuxtApp) => {
10+
const firebaseApp = nuxtApp.$firebaseApp as FirebaseApp
11+
12+
const [_user, auth] = _VueFireAuthInit(
13+
firebaseApp,
14+
nuxtApp.vueApp,
15+
nuxtApp.payload.vuefireUser as User | undefined,
16+
{
17+
errorMap:
18+
process.env.NODE_ENV === 'production' ? prodErrorMap : debugErrorMap,
19+
}
20+
)
21+
22+
return {
23+
provide: {
24+
firebaseAuth: auth,
25+
},
26+
}
27+
})

packages/nuxt/src/runtime/auth/plugin-mint-cookie.client.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
import type { FirebaseApp } from 'firebase/app'
21
import {
3-
getAuth,
42
onIdTokenChanged,
53
beforeAuthStateChanged,
64
type User,
5+
type Auth,
76
} from 'firebase/auth'
87
import { defineNuxtPlugin } from '#imports'
98

@@ -12,9 +11,8 @@ import { defineNuxtPlugin } from '#imports'
1211
* generate the proper auth state. **Must be added after the firebase auth plugin.**
1312
*/
1413
export default defineNuxtPlugin((nuxtApp) => {
15-
const firebaseApp = nuxtApp.$firebaseApp as FirebaseApp
14+
const auth = nuxtApp.$firebaseAuth as Auth
1615

17-
const auth = getAuth(firebaseApp)
1816
// send a post request to the server when auth state changes to mint a cookie
1917
beforeAuthStateChanged(
2018
auth,
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { VueFireAuthWithDependencies, _VueFireAuthKey } from 'vuefire'
2+
import { defineNuxtPlugin } from '#imports'
3+
import { inject } from 'vue'
4+
import {
5+
<% if(options.persistence) { %>
6+
<% options.persistence.forEach((persistenceName) => { %>
7+
<%= persistenceName %>Persistence,
8+
<% }) %>
9+
<% } %>
10+
11+
<% if(options.popupRedirectResolver) { %>
12+
<%= options.popupRedirectResolver %>PopupRedirectResolver,
13+
<% } %>
14+
15+
<% if(options.errorMap) { %>
16+
<%= options.errorMap %>ErrorMap,
17+
<% } %>
18+
} from 'firebase/auth'
19+
20+
/**
21+
* Setups VueFireAuth for the client. This version creates some listeners that shouldn't be set on server.
22+
*/
23+
export default defineNuxtPlugin((nuxtApp) => {
24+
const firebaseApp = nuxtApp.$firebaseApp
25+
26+
VueFireAuthWithDependencies({
27+
initialUser: nuxtApp.payload.vuefireUser,
28+
dependencies: {
29+
<% if(options.errorMap) { %>
30+
errorMap: <%= options.errorMap %>ErrorMap,
31+
<% } %>
32+
33+
<% if(options.persistence) { %>
34+
persistence: [
35+
<% options.persistence.forEach((persistenceName) => { %>
36+
<%= persistenceName %>Persistence,
37+
<% }) %>
38+
],
39+
<% } %>
40+
41+
<% if(options.popupRedirectResolver) { %>
42+
popupRedirectResolver: <%= options.popupRedirectResolver %>PopupRedirectResolver,
43+
<% } %>
44+
},
45+
})(firebaseApp, nuxtApp.vueApp)
46+
47+
return {
48+
provide: {
49+
firebaseAuth: nuxtApp.vueApp.runWithContext(() => inject(_VueFireAuthKey))
50+
},
51+
}
52+
})

packages/nuxt/src/runtime/auth/plugin.client.ts

Lines changed: 0 additions & 16 deletions
This file was deleted.

packages/nuxt/src/runtime/auth/plugin.server.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getAuth, signInWithCustomToken } from 'firebase/auth'
1+
import { signInWithCustomToken, getAuth, type Auth } from 'firebase/auth'
22
import {
33
type DecodedIdToken,
44
getAuth as getAdminAuth,
@@ -18,7 +18,7 @@ export default defineNuxtPlugin(async (nuxtApp) => {
1818
const firebaseApp = nuxtApp.$firebaseApp as FirebaseApp
1919
const firebaseAdminApp = nuxtApp.$firebaseAdminApp as AdminApp
2020
const adminAuth = getAdminAuth(firebaseAdminApp)
21-
const auth = getAuth(firebaseApp)
21+
const auth = nuxtApp.$firebaseAuth as Auth
2222

2323
const decodedToken = nuxtApp[
2424
// we cannot use a symbol to index
@@ -39,8 +39,8 @@ export default defineNuxtPlugin(async (nuxtApp) => {
3939
})
4040
// console.timeLog('token', `got token for ${user.uid}`)
4141
if (customToken) {
42-
const auth = getAuth(firebaseApp)
4342
logger.debug('Signing in with custom token')
43+
// TODO: allow user to handle error?
4444
await signInWithCustomToken(auth, customToken)
4545
// console.timeLog('token', `signed in with token for ${user.uid}`)
4646
// console.timeEnd('token')

0 commit comments

Comments
 (0)