I have the following problem with Vuex and Axios auth tokens.
It works fine in client side, but after page refresh the token is not set anymore, tho I think I get the user fine. But the store seems to be filled at first, but when I press "Time travel to this state" it becomes empty and I get logged out.
On top of this I'm getting a bunch of PAGE NOT FOUND errors in console everytime i refresh the page.
Any clues on whats going on? I've added my stores index.js file in the stackoverflow question above.
Thanks for any input!
store
won't be preserved after refreshing, you can combine store
with cookie
or session
to save the JWT, for further more information you can take a look at https://github.com/nuxt-community/auth-module or https://github.com/nuxt/example-auth0
You didin't even bother opening my code before closing? Great support. I'm storing the JWT in cookies and loading the state back from them, User state loads, but token wouldn't set in axios.
Sorry, NuxtServerInit
is right place to fetch token in server side, so when you refreshed pages, can fetchToken
get the ccmsToken
from cookie ?
It seems so.
Here's a screenshot of fetchToken action in store with console logs for token:
https://gyazo.com/89d7192c61e203e50b65e0536cdbb7d2
And here's the console log in nuxt console:
https://gyazo.com/67c9909e1f8eb5028a3457352d238e55
For some reason it gets called many times and alot of This page oculd not be found comes together with the refresh, maybe thats the root of the problem?
EDIT:
I think I found the problem.
its here:
https://gyazo.com/c7bb3d18553d7754e7fbec9ba6292db0
this.app.context.res.setHeader() , shouldn't we be setting the header on axios, not on context.res?
Perhaps it would help if I'd supply a demo site?
https://climatecms.herokuapp.com/login
demo, demo
and here's my update store/index.js
import Cookie from 'cookie'
import Cookies from 'js-cookie'
export const state = () => ({
sidebar: true,
token: null,
user: null
})
export const mutations = {
// SET SIDEBAR
toggleSidebar (state) {
state.sidebar = !state.sidebar
},
// SET USER
setUser (state, user) {
state.user = user
},
// SET TOKEN
setToken (state, token) {
state.token = token
}
}
export const getters = {
loggedIn (state) {
return Boolean(state.user && state.token)
}
}
export const actions = {
async nuxtServerInit ({ dispatch }, { req }) {
await dispatch('fetch')
},
// Update token
async updateToken ({ commit }, token) {
// Update token in store's state
commit('setToken', token)
// Set Authorization token for all axios requests
this.$axios.setToken(token, '')
// Update cookies
if (process.browser) {
// ...Browser
if (token) {
Cookies.set('ccmsToken', token, { expires: 1 })
} else {
Cookies.remove('ccmsToken')
}
} else {
// ...Server
let params = {
domain: '/'
}
if (!token) {
let expires
let date = new Date()
expires = date.setDate(date.getDate() + 1)
params.expires = new Date(expires)
}
this.$axios.defaults.headers.common['Authorization'] = token
this.app.context.res.setHeader('Authorization', Cookie.serialize('ccmsToken', token, params))
console.log('Axios: ', this.$axios.defaults.headers.common.Authorization)
}
},
// Fetch Token
async fetchToken ({ dispatch }) {
let token
// Try to extract token from cookies
if (!token) {
const cookieStr = process.browser ? document.cookie : this.app.context.req.headers.cookie
const cookies = Cookie.parse(cookieStr || '') || {}
token = cookies['ccmsToken']
}
if (token) {
await dispatch('updateToken', token)
}
if (process.browser) {
console.log('Browser token: ', token)
} else {
console.log('Server token: ', token)
}
},
// Reset
async reset ({ dispatch, commit }) {
commit('setUser', null)
await dispatch('updateToken', null)
},
// Fetch
async fetch ({ getters, state, commit, dispatch }, username = 'admin', { endpoint = 'https://climatecms-api.herokuapp.com/api/user' } = {}) {
// Fetch and update latest token
await dispatch('fetchToken')
// Skip if there is no token set
if (!state.token) {
return
}
// Try to get user profile
try {
const data = await this.$axios.$get(endpoint + '?username=' + username)
commit('setUser', data)
} catch (e) {
// Reset store
await dispatch('reset')
}
},
// Login
async login ({ dispatch }, { fields, endpoint = 'https://climatecms-api.herokuapp.com/api/login' } = {}) {
try {
// Send credentials to API
let data = await this.$axios.$post(endpoint, fields)
if (data.success) {
await dispatch('updateToken', data['token'])
// Fetch authenticated user
await dispatch('fetch', data.user.username)
} else {
throw new Error(data.message)
}
} catch (error) {
if (error.response && error.response.status === 401) {
throw new Error('Bad credentials')
}
throw error
}
},
// Logout
async logout ({ dispatch, state }) {
try {
await dispatch('reset')
} catch (e) {
console.error('Error while logging out', e)
}
}
}
Can you provide the middleware code or a demo repo ?
Can you try this.app.context.res.setHeader('Set-Cookie', Cookie.serialize('ccmsToken', token, params))
?
Can I provide you a repo privately? We can post the solution here after ofc.
Sure, you can create a provaite repo on github or gitlab,then give me a readable access.
I think I have granted You access on gitlab repo.
About the PAGE NOT FOUND
issue, it's a css source-map issue, you can add build.cssSourceMap: false
to turn off it or add vuetify
to vendor.
// nuxt.config.js
module.exports = {
build: {
cssSourceMap: false
}
// or
vendor: [
'~/plugins/vuetify.js',
'vuetify'
]
}
Have you fixed the refreshing issue ? Because I don't have you api service, so I hard-code the data and cannot reproduce the issue.
Maybe you can check if axios
in fetch
and login
can get the correct data, hence store.getters['loggedIn']
is true
You need to update the axios authorization header when refreshing the page. You can put this code into the axios plugin.
// axios.js (Plugin)
export default ({ store }) => {
axios.defaults.baseURL = {API endpoint}
if (process.server) {
return
}
axios.interceptors.request.use(request => {
request.baseURL = {API endpoint}
// Get token from auth.js store
const token = store.getters['auth/token']
// Update token axios header
if (token) {
request.headers.common['Authorization'] = `Bearer ${token}`
}
return request
})
})
@jay7793 Isin't this exactly what I'm doing on NuxtServerInit?
@clarkdo Hey, I will try this solution when I get back home. I can share the api with You as well, all it does on /login route is it checks if username and password match and then returns a JWT token along with the username, then I use username to fetch the user info from /users route. Thanks for the tip about source maps btw, It will probably solve the issue, didint think about this.
The problem persists. Everytime I go to Profile route which is "/" or "/admin" I'm getting 403. If I load these routes server side - everything works just fine. Any clues?
Heres both front-end and the api repos, if anyone has some time to check them out..
@clarkdo
@jay7793
https://github.com/Cogitoergo/ccms-front
https://github.com/Cogitoergo/ccms-api
Navigate to localhost:8000/setup to create a demo user with this info:
username: rytis
password: rytis
PS: the problem with the 404 not found still exists after disabling cssSourceMap or by adding vuetify to vendors (which is already added).
@Cogitoergo
The root cause of issue should be that in your nuxtServerInit
, fetch
didn't have a username
, so every server side initialization will fetch user admin
instead of rytis
.
You can extract real userName
from JWT and then fetch user info from api service.
Nah, changing it into just the token and getting the token decoded to get the username has the same effect, sadly. I noticed this, fixed it and still the same..
Sent from my iPhone
On 29 Jan 2018, at 04:23, Clark Du notifications@github.com wrote:
@Cogitoergo
The root cause of issue should be that in your nuxtServerInit, fetch didn't have a username, so every server side initialization will fetch user admin instead of rytis.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or mute the thread.
For testing, I just set it to 'rytis' and disabled cssSourceMap
, it works fine for me.
Many thanks for trying, but I will try to reproduce the error for You in
video format in an hour or so, as I'm still getting the same 403.. Its
really, really strange.. This store setup is a copy paste from @nuxtjs/auth
module,all I did is I modified the Cookie expiration to 1 day, as
previously it was 0, so I had no cookie to get my auth info from on SSR. Or
am I missing something? Perhaps cookie expiration is supposed to be only
session and I should get the auth data in SSR in some other way?
On 29 January 2018 at 08:08, Clark Du notifications@github.com wrote:
For testing, I just set it to 'rytis' and disabled cssSourceMap, it works
fine for me.—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/nuxt/nuxt.js/issues/2680#issuecomment-361148962, or mute
the thread
https://github.com/notifications/unsubscribe-auth/AMAWhjGp3koS8I_-UZcoNVmZ4vV4TmGTks5tPWBTgaJpZM4Rq7sJ
.
--
Pagarbiai,
Karolis StakÄ—nas
Skype:karolis.stakenas
@clarkdo
Buddy, I've added you to my gitlab repos for both front and back end. I updated them with the fixes You've mentioned.
I'm extracting the user from token now.. Still the same issue. Altho, it doesn't always come up.
Try reaching / or /admin routes. If I load them server side - it works perfectly. I can refresh the page, it all shows up. But when I navigate out to say /posts route, then coming back to / or /admin via profile dropdown in the upper right corner - it gives me 403..
EDIT: I narrowed the problem down. It seems, that it works fine with SSR, works fine with only Client-Side. Where it fails is to set the client token when rendered server-side. So if I load /admin directly, it works, but every other client-side request fails. If I load web with SSR, press logout, then log back in - everything works well up till first refresh. When I refresh say admin page, I still get the admin page data (list of users), but when I navigate to profile ('/'), it fails with the same 403.
The web is reachable here : https://climatecms.herokuapp.com
user: demo
password: demo
I'm so lost on this, damn.
@jay7793 Man, thank You very much! This actually solved my problem, I don't know why I turned a blind eye on this at first.
Hello, I am also the problem, how to solve
@Cogitoergo
how did you solved this issue will be more helpful if you explain in detail. im new to nuxtjs and facing same issue with token on refresh page.
I solved it exactly how I explained it in the stackoverflow post. Dont be lazy.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
You need to update the axios authorization header when refreshing the page. You can put this code into the axios plugin.