Skip to content

Commit 7db1c19

Browse files
authored
Merge pull request #70 from lupas/dev
added getAuthUserFromCookie() and SSR feature for firebase auth
2 parents a932e10 + b7bde44 commit 7db1c19

File tree

7 files changed

+134
-36
lines changed

7 files changed

+134
-36
lines changed

packages/docs/.vuepress/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ module.exports = {
1010
'/getting-started/',
1111
'/options/',
1212
'/usage/',
13+
'/helpers/',
1314
'/advanced/',
1415
'/demo/'
1516
],

packages/docs/advanced/README.md

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,49 @@
11
# Advanced
22

3-
## Helpers
3+
## Firebase Auth in Universal Mode
44

5-
Nuxt-Fire provides helper functions that can generally be accessed like so:
5+
The nuxt-fire plugin provides helpers for the easy setup of **server-side authentication** via WebTokens and Cookies for Firebase Auth in **Nuxt Universal Mode (SSR)**.
66

7-
```js
8-
import { **helperFunctionName** } from 'nuxt-fire/src/helpers'
9-
```
7+
#### Step 1 - Initialize Firebase Auth
108

11-
### movePluginBeforeInitAuthPlugin(plugins, pluginName)
9+
Use the [auth.initialize option](/options/#auth) with at least `onSuccessMutation` and `setAuthCookie = true` defined. Make sure to create the respective mutation that saves the authUser to the state.
1210

13-
If the initAuth config is set, nuxt-fire will add two (instead of one) plugins to your Nuxt application:
14-
**nuxt-fire/plugins/main.js** and **nuxt-fire/plugins/initAuth.js**.
11+
#### Step 2 - Add the getAuthUserFromCookie() helper
1512

16-
If you use initAuth and want another plugin to be called AFTER firebase initialization but BEFORE initAuth gets called, you can use this helper function to move the other plugin inbetween these two.
17-
18-
Just add the following to your nuxt.config.js:
13+
Add the `getAuthUserFromCookie()` helper function as follows to your nuxtServerInit action and commit the authUser object to the mutation defined in step 1.
1914

2015
```js
21-
import { movePluginBeforeInitAuthPlugin } from 'nuxt-fire/src/helpers'
16+
import { getAuthUserFromCookie } from 'nuxt-fire/src/helpers'
17+
18+
export default {
19+
nuxtServerInit({ commit }, ctx) {
20+
const authUser = getAuthUserFromCookie({ commit, req: ctx.req })
21+
if (authUser) {
22+
commit('SET_AUTH_USER', {
23+
authUser
24+
})
25+
}
26+
}
27+
}
28+
```
2229

23-
extendPlugins(plugins) {
24-
movePluginBeforeInitAuthPlugin(plugins, 'yourPluginName.js')
25-
return plugins
26-
},
30+
#### Step 3 - Delete cookie at logout
31+
32+
Make sure to delete the cookie at logout, e.g. in an action:
33+
34+
```js
35+
import Cookie from "js-cookie";
36+
37+
async logoutUser({ commit }) {
38+
await this.$fireAuth.signOut()
39+
// Reset store
40+
commit("RESET_STORE");
41+
// ADD THIS LINE
42+
Cookie.remove("nuxt_fire_auth_access_token");
43+
}
44+
}
2745
```
2846

2947
## Usage with vuexfire
3048

31-
This [example](https://github.com/lupas/nuxt-fire-vuexfire-example) shows how to use both vuexfire and nuxt-fire together.
49+
This [example](https://github.com/lupas/nuxt-fire-vuexfire-example) shows how to use both vuexfire and nuxt-fire together, working with SSR.

packages/docs/helpers/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Helpers
2+
3+
Nuxt-Fire provides helper functions that can generally be accessed like so:
4+
5+
```js
6+
import { **helperFunctionName** } from 'nuxt-fire/src/helpers'
7+
```
8+
9+
## movePluginBeforeInitAuthPlugin()
10+
11+
If the initAuth config is set, nuxt-fire will add two (instead of one) plugins to your Nuxt application:
12+
**nuxt-fire/plugins/main.js** and **nuxt-fire/plugins/initAuth.js**.
13+
14+
If you use initAuth and want another plugin to be called AFTER firebase initialization but BEFORE initAuth gets called, you can use this helper function to move the other plugin inbetween these two.
15+
16+
Just add the following to your nuxt.config.js:
17+
18+
```js
19+
import { movePluginBeforeInitAuthPlugin } from 'nuxt-fire/src/helpers'
20+
21+
extendPlugins(plugins) {
22+
movePluginBeforeInitAuthPlugin(plugins, 'yourPluginName.js')
23+
return plugins
24+
},
25+
```
26+
27+
## getAuthUserFromCookie()
28+
29+
Parses the request cookie named `nuxt_fire_auth_access_token` in the nuxtServerInit action and returns an authUser object, if user is signed in.
30+
31+
For usage see [here](/advanced/#firebase-auth-in-universal-mode).
32+
33+
```js
34+
import { getAuthUserFromCookie } from 'nuxt-fire/src/helpers'
35+
// in nuxtServerInit
36+
const authUser = getAuthUserFromCookie(req)
37+
```

packages/docs/options/README.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,6 @@ Preloads dynamically loaded services. More information [here](https://webpack.js
130130
Only applies if `static === false`.
131131
:::
132132

133-
134-
135133
#### chunkName
136134

137135
Be default, the dynamically imported services are named `vendors.firebase-${serviceName}.js` in development mode, and `[id]` in production mode (`process.env.NODE_ENV === 'production'`). If you want to change this behaviour, you can do so with this option.
@@ -157,17 +155,14 @@ auth: {
157155
onSuccessMutation: 'ON_SUCCESS_MUTATION',
158156
onSuccessAction: null,
159157
onErrorMutation: null,
160-
onErrorAction: 'onErrorAction'
158+
onErrorAction: 'onErrorAction',
159+
setAuthCookie: false // default
161160
}
162161
}
163162
```
164163

165164
#### initialize <Badge text="EXPERIMENTAL" type="warn"/>
166165

167-
::: warning <Badge text="EXPERIMENTAL FEATURE" type="warn"/>
168-
This feature is experimental and has not been fully tested for all cases. Use it with care and don't use it in production environemnts. It might get changed completely in future updates. If you have any issues or questions for this feature please feel free to create an issue [here](https://github.com/lupas/nuxt-fire/issues) to help us improve it.
169-
:::
170-
171166
This sets up SSR-ready `onAuthStateChanged()` without any effort.
172167

173168
Just add a mutation/action to your vuex store that handles what to do with the authUser object (e.g. save it to the state or get user data from FireStore) and then define the name of the action/mutation in the initAuth configuration as below
@@ -192,20 +187,23 @@ onErrorAction: (ctx, error) => {
192187
}
193188
```
194189

190+
The `setAuthCookie = true` option sets a cookie after every `onAuthStateChanged()` trigger. The cookie can be used for server-side authentication as described [here](/advanced/#firebase-auth-in-universal-mode).
191+
195192
::: warning
196193
Do not save `authUser` directly to the store, since this will save an object reference to the state which gets directly updated by Firebase Auth periodically and therefore throws a `vuex` error if `strict != false`.
197194

198195
```js
199196
export const mutations = {
200-
onSuccessMutation: (state, { authUser, claims }) => {
201-
// Don't do this:
202-
state.user = authUser,
203-
// Do this:
204-
state.user.id = authUser.uid,
205-
state.user.email = authUser.email
206-
}
197+
onSuccessMutation: (state, { authUser, claims }) => {
198+
// Don't do this:
199+
state.user = authUser
200+
// Do this:
201+
state.user.id = authUser.uid
202+
state.user.email = authUser.email
203+
}
207204
}
208205
```
206+
209207
:::
210208

211209
### firestore
@@ -269,7 +267,7 @@ More information [here](https://firebase.google.com/docs/functions/locations).
269267

270268
Sets up `useFunctionsEmulator("http://localhost:EMULATOR_PORT")` to point to a Cloud Functions emulator running locally instead of the productive one.
271269

272-
More information in the official Firebase [API Docs](https://firebase.google.com/docs/reference/android/com/google/firebase/functions/FirebaseFunctions.html#useFunctionsEmulator(java.lang.String)) and [Functions Docs](https://firebase.google.com/docs/functions/local-emulator).
270+
More information in the official Firebase [API Docs](<https://firebase.google.com/docs/reference/android/com/google/firebase/functions/FirebaseFunctions.html#useFunctionsEmulator(java.lang.String)>) and [Functions Docs](https://firebase.google.com/docs/functions/local-emulator).
273271

274272
### storage
275273

packages/nuxt-fire/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nuxt-fire",
3-
"version": "3.3.0",
3+
"version": "3.4.0",
44
"license": "MIT",
55
"description": "Intergrate Firebase into your Nuxt project.",
66
"main": "src/index.js",
@@ -19,6 +19,9 @@
1919
"firebase": "^7.5.0"
2020
},
2121
"dependencies": {
22+
"cookieparser": "^0.1.0",
23+
"js-cookie": "^2.2.1",
24+
"jwt-decode": "^2.2.0",
2225
"lodash": "^4.17.15"
2326
}
2427
}

packages/nuxt-fire/src/helpers/index.js

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
export function movePluginBeforeInitAuthPlugin(plugins, pluginName) {
2-
// Moves a plugin that needs access to $this.fireFOO but needs to get run BEFORE nuxt-auth in between the nuxt-fire and the auth plugin.
3-
// This function needs to be applied in extendPlugins in nuxt.config.js.
1+
import cookieparser from 'cookieparser'
2+
import JWTDecode from 'jwt-decode'
43

4+
/**
5+
* Moves a plugin that needs access to $this.fireFOO but needs to get run BEFORE
6+
* nuxt-auth in between the nuxt-fire and the auth plugin.
7+
* This function needs to be applied in extendPlugins in nuxt.config.js.
8+
*/
9+
export function movePluginBeforeInitAuthPlugin(plugins, pluginName) {
510
const indexOfPluginToMove = _getPluginIndex(plugins, pluginName)
611
const indexOfNuxtFirePlugin = _getPluginIndex(plugins, 'nuxt-fire/main')
712

@@ -34,3 +39,29 @@ function _getPluginIndex(plugins, pluginName) {
3439
}
3540
return plugins.findIndex((x) => includesPlugin(x))
3641
}
42+
43+
/**
44+
* Parses the request cookie and returns an authUser, if user is signed in.
45+
*/
46+
export function getAuthUserFromCookie({ req }) {
47+
if (process.server && process.static) return
48+
if (!req.headers.cookie) return
49+
50+
const cookie = cookieparser.parse(req.headers.cookie)
51+
const accessWebToken = cookie.nuxt_fire_auth_access_token
52+
53+
if (!accessWebToken) return
54+
55+
const decodedAuthUser = JWTDecode(accessWebToken)
56+
// Note: Not the same authUser Object as .currentUser from the Firebase Auth SDK.
57+
58+
// Trying to "recreate" the authUser object as similarly as possible
59+
// from available data we received from the web token:
60+
const authUser = {
61+
uid: decodedAuthUser.user_id,
62+
email: decodedAuthUser.email,
63+
emailVerified: decodedAuthUser.email_verified
64+
}
65+
66+
return authUser
67+
}

packages/nuxt-fire/src/plugins/initAuth.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import Cookie from "js-cookie";
2+
13
export default async ({ store, app }) => {
24
const options = <%= serialize(options) %>
35

@@ -9,6 +11,9 @@ export default async ({ store, app }) => {
911
if (authUser) {
1012
try {
1113
await _handleAuthSuccess(authUser)
14+
if (options.setAuthCookie) {
15+
_setAuthCookie(authUser)
16+
}
1217
} catch (e) {
1318
await _handleAuthError(e)
1419
Promise.reject(e)
@@ -23,6 +28,11 @@ export default async ({ store, app }) => {
2328
/** -------------------------------------- Local Functions -------------------------------------- **/
2429
/** --------------------------------------------------------------------------------------------- **/
2530

31+
async function _setAuthCookie(authUser) {
32+
const token = await authUser.getIdToken()
33+
Cookie.set("nuxt_fire_auth_access_token", token)
34+
}
35+
2636
async function _handleAuthSuccess(authUser) {
2737
const onSuccessMutation = options.onSuccessMutation
2838
const onSuccessAction = options.onSuccessAction

0 commit comments

Comments
 (0)