Skip to content

Commit b81dff0

Browse files
committed
fix(auth): only add mint cookie endpoint with admin sdk
1 parent b6d7ad5 commit b81dff0

File tree

3 files changed

+64
-51
lines changed

3 files changed

+64
-51
lines changed

packages/nuxt/src/module.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -106,14 +106,6 @@ const VueFire: NuxtModule<VueFireNuxtModuleOptions> =
106106
nuxt.options.build.transpile.push('vuefire')
107107
nuxt.options.build.transpile.push('vuefire/server')
108108

109-
// Add the session handler than mints a cookie for the user
110-
if (nuxt.options.ssr) {
111-
addServerHandler({
112-
route: '/api/__session',
113-
handler: resolve(runtimeDir, './auth/api.session'),
114-
})
115-
}
116-
117109
// This one is set by servers, we set the GOOGLE_APPLICATION_CREDENTIALS env variable instead that has a lower priority and can be both a path or a JSON string
118110
// process.env.FIREBASE_CONFIG ||= JSON.stringify(options.config)
119111
if (typeof options.admin?.serviceAccount === 'string') {
@@ -135,6 +127,17 @@ const VueFire: NuxtModule<VueFireNuxtModuleOptions> =
135127
)
136128
}
137129

130+
// Add the session handler than mints a cookie for the user
131+
if (nuxt.options.ssr && hasServiceAccount) {
132+
addServerHandler({
133+
route: '/api/__session',
134+
handler: resolve(runtimeDir, './auth/api.session'),
135+
})
136+
137+
// must be added after (which means before in code) the plugin module
138+
addPlugin(resolve(runtimeDir, 'auth/plugin-mint-cookie.client'))
139+
}
140+
138141
addPlugin(resolve(runtimeDir, 'auth/plugin.client'))
139142
// must be added after the admin module to use the admin app
140143
addPlugin(resolve(runtimeDir, 'auth/plugin.server'))
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { FirebaseApp } from 'firebase/app'
2+
import {
3+
getAuth,
4+
onIdTokenChanged,
5+
beforeAuthStateChanged,
6+
User,
7+
} from 'firebase/auth'
8+
import { defineNuxtPlugin } from '#app'
9+
10+
/**
11+
* Sets up a watcher that mints a cookie based auth session. On the server, it reads the cookie to
12+
* generate the proper auth state. **Must be added after the firebase auth plugin.**
13+
*/
14+
export default defineNuxtPlugin((nuxtApp) => {
15+
const firebaseApp = nuxtApp.$firebaseApp as FirebaseApp
16+
17+
const auth = getAuth(firebaseApp)
18+
// send a post request to the server when auth state changes to mint a cookie
19+
beforeAuthStateChanged(
20+
auth,
21+
// if this fails, we rollback the auth state
22+
mintCookie,
23+
() => {
24+
// rollback the auth state
25+
mintCookie(auth.currentUser)
26+
}
27+
)
28+
29+
// we need both callback to avoid some race conditions
30+
onIdTokenChanged(auth, mintCookie)
31+
})
32+
33+
// TODO: should this be throttled to avoid multiple calls
34+
/**
35+
* Sends a post request to the server to mint a cookie based auth session. The name of the cookie is defined in the
36+
* api.session.ts file.
37+
*
38+
* @param user - the user to mint a cookie for
39+
*/
40+
async function mintCookie(user: User | null) {
41+
const jwtToken = await user?.getIdToken(/* forceRefresh */ true)
42+
// throws if the server returns an error so that beforeAuthStateChanged can catch it to cancel
43+
await $fetch(
44+
// '/api/__session-server',
45+
'/api/__session',
46+
{
47+
method: 'POST',
48+
// if the token is undefined, the server will delete the cookie
49+
body: { token: jwtToken },
50+
}
51+
)
52+
}
Lines changed: 1 addition & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,12 @@
11
import type { FirebaseApp } from 'firebase/app'
2-
import {
3-
getAuth,
4-
onIdTokenChanged,
5-
beforeAuthStateChanged,
6-
User,
7-
} from 'firebase/auth'
82
import { VueFireAuth } from 'vuefire'
93
import { defineNuxtPlugin } from '#app'
104

115
/**
12-
* Setups VueFireAuth and automatically mints a cookie based auth session. On the server, it reads the cookie to
13-
* generate the proper auth state.
6+
* Setups VueFireAuth for the client.
147
*/
158
export default defineNuxtPlugin((nuxtApp) => {
169
const firebaseApp = nuxtApp.$firebaseApp as FirebaseApp
1710

1811
VueFireAuth(nuxtApp.payload.vuefireUser)(firebaseApp, nuxtApp.vueApp)
19-
const auth = getAuth(firebaseApp)
20-
// send a post request to the server when auth state changes to mint a cookie
21-
beforeAuthStateChanged(
22-
auth,
23-
// if this fails, we rollback the auth state
24-
mintCookie,
25-
() => {
26-
// rollback the auth state
27-
mintCookie(auth.currentUser)
28-
}
29-
)
30-
31-
// we need both callback to avoid some race conditions
32-
onIdTokenChanged(auth, mintCookie)
3312
})
34-
35-
// TODO: should this be throttled to avoid multiple calls
36-
/**
37-
* Sends a post request to the server to mint a cookie based auth session. The name of the cookie is defined in the
38-
* api.session.ts file.
39-
*
40-
* @param user - the user to mint a cookie for
41-
*/
42-
async function mintCookie(user: User | null) {
43-
const jwtToken = await user?.getIdToken(/* forceRefresh */ true)
44-
// throws if the server returns an error so that beforeAuthStateChanged can catch it to cancel
45-
await $fetch(
46-
// '/api/__session-server',
47-
'/api/__session',
48-
{
49-
method: 'POST',
50-
// if the token is undefined, the server will delete the cookie
51-
body: { token: jwtToken },
52-
}
53-
)
54-
}

0 commit comments

Comments
 (0)