Open mategvo opened 4 years ago
However picks this up, many thanks in advance for support. We are currenlty solving the problem in default.vue template
async created() {
await this.authenticate()
.then(() => {
// todo - redirect to where the user came from
this.$router.push('/events')
})
.catch((e) => {
console.log('not authenticated')
this.logout()
})
},
but we are now having problems with redirects.
Could this be related to this issue?
Same problem with the lastest version of feathers-vuex and nuxt SSR
I've created a plugin to solve this problem. It works with localstorage. Needs to be edited slighltly for cookie storage
// ~/plugins/authInit.js
const storedToken = typeof localStorage['feathers-jwt'] !== 'undefined'
const hashTokenAvailable = window.location.hash.indexOf('access_token' > -1)
export default async (context) => {
if (
(!context.app.store.state.auth.user && storedToken) ||
hashTokenAvailable
) {
console.log('Authenticating', context.app.store.state.auth.user)
await context.app.store
.dispatch('auth/authenticate')
.then(() => {
console.log('Authenticated', context.app.store.state.auth.user)
})
.catch((e) => {
console.error(e)
})
}
}
Remember to initialize it in nuxt.config.js
// nuxt.config.js
plugins: [
{ src: '~/plugins/authInit.js', ssr: false }
],
Here's the version for cookies-storage
// ~/plugins/authInit.js
import { CookieStorage } from 'cookie-storage'
const cookieStorage = new CookieStorage()
const cookie = cookieStorage.getItem('feathers-jwt') !== null
const hashTokenAvailable = window.location.hash.indexOf('access_token' > -1)
export default async (context) => {
if ((!context.app.store.state.auth.user && cookie) || hashTokenAvailable) {
console.log('Authenticating', context.app.store.state.auth.user)
await context.app.store
.dispatch('auth/authenticate')
.then(() => {
console.log('Authenticated', context.app.store.state.auth.user)
})
.catch((e) => {
console.error(e)
})
}
}
Hope this helps
@mateuszgwozdz could you find some time to add your solution to what you see as the best place for it in the Feathers-Vuex Nuxt docs? I've been doing more and more work with Gridsome's pre-rendering, so I'm a little out of the loop with Nuxt. No worries if not. I will leave this open.
Sure, I will do it with pleasure. I just thought that something is not working as supposed to for me, rather than it's a missing functionality
I put this in the docs in a quite early place, related to auth. It's becuase I assumed this functionality is included and actually lost significant amount of time trying to "fix" it, find a bug. I think it will prevent others from misunderstanding this feature. Still I believe this is something that should work out-of-the-box. I can also write the plugin in the way that automatically determines whether we are using localstorage or cookie and restores the session - would that be useful as out-of-the-box feature?
https://github.com/feathersjs-ecosystem/feathers-vuex/compare/master...mateuszgwozdz:patch-1
@mateuszgwozdz Unfortunately that patch doesn't work for me with using https://vuex.feathersjs.com/nuxt.html#full-nuxt-configuration-example.
Interestingly though I can only replicate this with nuxt
(dev mode) not when running on production with nuxt build && nuxt start
.
Doesn't work for you with SSR you mean? My project is a simple SPA, I forgot to mention I haven't tested SSR, I don't think it will work
I can confirm it works for me fine in nuxt start
. I reload live website and I am still authenticated
Doesn't work for you with SSR you mean? My project is a simple SPA, I forgot to mention I haven't tested SSR, I don't think it will work
That's right I'm using 'universal' mode with Nuxt, but only when in dev mode not production do I see the issue anyway.
Hey guys I wanted to share a workaround that worked for me to get authenticated server side whereas @mategvo's solution will only work client side which can cause problems.
The root of the problem comes from the fact that cookie-storage
requires document
to work properly which will not work server side to parse the feathers-jwt
token.
Compounding that fact is that plugins/feathers
from the full nuxt example has .configure(auth({ storage }))
which isn't yet aware of the req
variable required to parse cookies server side so I cooked up a workaround. Bear in mind that this isn't fully tested yet so there could be some gotchas further down the road so if you see one let me know.
First off, replace cookie-storage
with universal-cookie
Then give it a decorate it with the required methods
class CookieStorage extends Cookies {
get getItem() { return this.get; }
get setItem() { return this.set; }
get removeItem() { return this.remove; }
}
Then, install cookie-universal-nuxt
and refactor @mategvo 's code so that it will work on the server side too.
Here's my full workaround:
// ~/plugins/authInit.js
import { storage } from './feathers';
const hashTokenAvailable = process.client && window.location.hash.indexOf('access_token' > -1);
export default async ({ store, $cookie }) => {
// Give the cookie to the auth module's storage instance
const cookie = $cookie.get('feathers-jwt');
if (cookie) {
storage.set('feathers-jwt', cookie);
}
if ((!store.state.auth.user && cookie) || hashTokenAvailable) {
await store
.dispatch('auth/authenticate')
.then(() => {
console.log('Authenticated');
})
.catch((e) => {
console.error(e)
})
}
}
// ~/plugins/feathers.js
import feathers from '@feathersjs/feathers'
import rest from '@feathersjs/rest-client'
import axios from 'axios'
import socketio from '@feathersjs/socketio-client'
import auth from '@feathersjs/authentication-client'
import io from 'socket.io-client'
import Cookies from 'universal-cookie';
import { iff, discard } from 'feathers-hooks-common'
import feathersVuex, { initAuth, hydrateApi } from 'feathers-vuex'
const apiUrl = process.env.API_URL;
let socket
let restClient
// We won't use socket to comunicate from server to server
if (process.client) {
socket = io(apiUrl, { transports: ['websocket'] })
} else {
restClient = rest(apiUrl)
}
const transport = process.client ? socketio(socket) : restClient.axios(axios)
class CookieStorage extends Cookies {
get getItem() { return this.get; }
get setItem() { return this.set; }
get removeItem() { return this.remove; }
// and any other required method as needed
}
const storage = new CookieStorage()
const feathersClient = feathers()
.configure(transport)
.configure(auth({ storage }))
.hooks({
before: {
all: [
iff(
context => ['create', 'update', 'patch'].includes(context.method),
discard('__id', '__isTemp')
)
]
}
})
export default feathersClient
// Setting up feathers-vuex
const { makeServicePlugin, makeAuthPlugin, BaseModel, models, FeathersVuex } = feathersVuex(
feathersClient,
{
serverAlias: 'api', // optional for working with multiple APIs (this is the default value)
idField: '_id', // Must match the id field in your database table/collection
whitelist: ['$regex', '$options'],
enableEvents: process.client // Prevent memory leak
}
)
export {
makeAuthPlugin,
makeServicePlugin,
BaseModel,
models,
FeathersVuex,
initAuth,
hydrateApi,
storage,
}
Obviously not the best solution here; hoping this SSR oversight gets fixed later.
Steps to reproduce
(First please check that this issue is not already solved as described here)
Expected behavior
If user is signed in, a page refresh should keep them logged in.
Actual behavior
User is not authenticated, regardless of jwt-token being stored in localStorage or cookies
System configuration
Latest nuxt js and feathers vuex Node feathers API
nuxt.config.js:
store/index.js (as per official documentation)
Module versions (especially the part that's not working):
NodeJS version: v12.15.0
Operating System:
macos & docker
Browser Version: Latest Chrome
React Native Version: no react
Module Loader: NPM