Comments (38)
You are on a right way. The only change required for that plugin is that you can directly access app.$axios
and call setToken
on it. No need to import/export.
plugins/auth.js
export default ({store, app: { $axios }}) => {
$axios.setToken(store.state.token)
}
from axios-module.
I spent a few hours today trying to figure this out and think I finally have a working solution for Nuxt 2.6.3. I have an store for the auth token and current user. YMMV with this code since I don't really know what I'm doing.
store/index.js
export const actions = {
async nuxtServerInit ({ dispatch, commit }) {
const token = this.$cookies.get('x-access-token')
if (token) {
try {
await commit('auth/setToken', token)
await dispatch('auth/fetchUser', token)
} catch(e) {
console.log(e)
await dispatch('auth/logout')
}
}
}
}
store/auth.js
export const state = () => ({
user: null,
token: null
})
export const mutations = {
setUser(store, user) {
store.user = user
},
resetUser(store) {
store.user = null
},
setToken(store, token) {
store.token = token
},
resetToken(store) {
store.token = null
}
}
export const actions = {
async fetchUser({ commit }, token) {
const { data } = await this.$axios.get('auth/me')
commit('setUser', data)
},
async login({ commit }, id) {
const { data } = await this.$axios.post('auth/login', { id: id })
commit('setUser', data.user)
commit('setToken', data.token)
this.$cookies.set('x-access-token', data.token, {
maxAge: 60 * 60
})
},
async logout({ commit }) {
commit('resetUser')
commit('resetToken')
this.$cookies.remove('x-access-token')
}
}
plugins/axios.js
export default function ({ $axios, store, redirect }) {
$axios.onRequest(config => {
const token = store.state.auth.token
if (token) config.headers.common['Authorization'] = `Bearer ${token}`
console.log('Request:')
console.log(config)
})
$axios.onResponse(response => {
console.log('Response:')
console.log(response)
})
$axios.onError(error => {
const code = parseInt(error.response && error.response.status)
if (code === 400) {
redirect('/400')
}
})
}
middleware/auth_required.js
export default function ({ store, redirect }) {
if (!store.state.auth.user) {
return redirect('/login')
}
}
The key to get this working is to ensure that I commit the token before the current user, since my middleware checks the latter, and to use the async in nextServerInit
, which I think blocks the middleware from processing. I'm not positive on this detail, though, and would appreciate any feedback on this code.
from axios-module.
Same thing here, I do a this.$axios.setToken(token, 'Bearer')
in nuxtServerInit() then the authorization header disappears on client side :(
from axios-module.
@m4tty-d I don't know what the recommended way but I am using this with success:
plugins/axios.js:
export default function ({ $axios, app, store }) {
$axios.onRequest(config => {
if (store.state.authToken) {
config.headers.common['Authorization'] = store.state.authToken
}
})
}
from axios-module.
Hope this helps someone:
i have this:
/plugins/axios.js
import axios from 'axios';
function tokenHandler(config, store) {
if (store.state.account.user && store.state.account.user.jwt) {
config.headers.common['Authorization'] = `Bearer ${store.state.account.user.jwt}`;
}
return config
}
export default (context) => {
//store is the current store, both server and client side. and unique for nuxtServerInit
let {store, app} = context;
axios.interceptors.request.use(config => tokenHandler(config, store),
function (error) {
return Promise.reject(error);
});
}
Of course add the 'plugin' to your nuxt.config.js
plugins: [
'@/plugins/vuetify',
'@/plugins/axios' <--
],
and inside the nuxtServerInit i set the needed store values (from cookies for example)
This is just a more complete example of some of the suggestions elsewhere..
from axios-module.
Interesting.
I do have a working version on my project right now. My approach was to set the token into the store during nuxtserverinit and then set the token again in the plugin for the client.
plugin
export default ({store, $axios}) => {
$axios.setToken(store.state.token)
}
nuxtServerInit
nuxtServerInit ({commit}, {req, route, app, store}) {
let cookies = new Cookies(req)
let token = cookies.get('access-token')
if (!token) return
commit('setToken', token)
app.$axios.setToken(token, 'Bearer')
}
from axios-module.
@pi0 the same problem as @uptownhr has.
After $axios.setToken on the server side, the $axios instance loses token on the client side.
Could you explain, how to use the "magic" feature of the setting once?
from axios-module.
Hello @pi0
I am confused. Do I need to call $axios.setToken both on SSR and CSR?
I ask becouse now I have o code like this, plugin:
export default function ({ store, route, redirect, req, res, isClient, isServer, app: { $axios } }) {
if (isServer) {
const cookies = new Cookies(req, res)
authToken = cookies.get(AUTH_TOKEN_KEY)
if (authToken) {
$axios.setToken(authToken)
}
[...]
}
And the user is logged correctly. But later for CSR axios don't send Authorization header. Why is it?
When I add this to the plugin everything works fine:
if (isClient && authToken) {
$axios.setToken(authToken, 'Bearer')
}
from axios-module.
@awronski As of rc2
we have a magical feature which allows doing that once. Just give us little more time as there are lots of works while preparing final release :)
from axios-module.
Axios module has a new home and finally, SSR is safe to use setToken
and setHeader
. The main cause was totally crazy! commit and this commit.
Upgrade to >= 3.1.3
is recommended for everyone!
yarn add @nuxtjs/axios@^3.1.3
# or
npm i @nuxtjs/axios@^3.1.3
from axios-module.
@awronski As of rc2 we have a magical feature which allows doing that once. Just give us little more time as there are lots of works while preparing final release :)
@pi0 i'm on rc8 and tried to use this magical feature of using setToken just once. Can you walk me through this? Currently i'm calling setToken from the nuxtServerInit app.$axios.setToken
. Works went request is made from the server but client looses the token.
from axios-module.
from axios-module.
Is there any reason why $axios can't automatically take the token from eg. localStorage
or app.$auth.$storage
at runtime?
After days of debugging, I finally figured out how to...
- Get a new authorization token for Auth0 tokens that are almost exported, using the silent renewal process
- Update the token in my LocalStorage
- Update the token in my
app.$auth.$storage
state
I could not find ANY documentation on how to do this and kinda had to reverse-engineer the Nuxt Auth module & the Auth0.js library to get to this point.
I expected everything to finally work... only to realize that my app was STILL breaking.
Apparently, I also had to call app.$axios.setToken
with the new token after my previous steps, so Axios would use the correct token.
How is anyone supposed to figure this out on their own?
from axios-module.
I tried to provide a solution that did not know if it was feasible.
from axios-module.
@pi one more question. It the global variables shared between concurrent requests fixed in the rc.3?
I have strange behavior.
Plugin code:
export default function ({ store, route, app: { $axios } }) {
console.log( $axios.defaults.headers.common.Authorization )
[...]
}
- I log user lets say with the Chrome browser.
- Than I access the page with the IE browser (without login)
- In the console log of the server I see Bearer of the first user.
In the CSR the tokens are set correctly.
from axios-module.
@opgbaudouin thanks a lot for this. Searched for two hours how to do this.
from axios-module.
one solution for me was to create an axios plugin that exports $axios
let axios = null
export default ({store, $axios}) => {
console.log('axios plugin init')
$axios.setToken(store.state.token)
axios = $axios
}
export {
axios
}
now i'm able to import {axios} from '~plugins/axios'
again.
Looks a bit weird for me so would love some feedback if this is a bad approach.
from axios-module.
@seekcx I've seen that PR. But directly integration of store into axios makes it optinized and maybe not everyone wants using vuex
in their project. We need an enhancement in Nuxt core indeed that plugins need a way adding things to __NUXT__
variable and access it on client init. Meanwhile whats wrong with simply using per-project plugins like above to call setToken with store state?
from axios-module.
@pi0 Sorry, just did not pay attention to see you on a comment, really perfect solution to this problem.
from axios-module.
@pi0 the export import was added in for a different reason. It was so I can import from my store so I don't have to pass in axios to all my actions.
I remember you mentioned there is an issue with this approach. Is there an issue or is this an OK approach?
from axios-module.
Also what is the difference between accessing $axios from the context vs grabbing from ctx.app
from axios-module.
@uptownhr It works but unsafe for SSR. (Because global variables will be shared between concurrent requests and this is probably not what we want!). We can access token from context only ( $axios, app, store, etc )
from axios-module.
from axios-module.
from axios-module.
@uptownhr The problem is the axios module use defaults internally. Just check:
https://github.com/nuxt-community/modules/blob/master/modules/axios/plugin.js#L33
In the present implementation the module cannot be use on server. Therefore I cannot hydrate the store for server side rendering.
I am thinking about diffrent implementation. Where the token is not put in the axios defaults but retrived from the store from axios interceptors. This should be thread safe.
from axios-module.
@uptownhr Hi James!
thanks for sharing your code.
Your example is working but I think it is not correct.
You set token in the nuxtServerInit, so the token is set on the shared axios server instance.
The same for every client.
In my opinion this is potentially security problem.
from axios-module.
I did a quick fix inside the nuxtjs/axios/plugin.js:
function tokenHandler(config, store) {
if (store.getters.authToken) {
config.headers.common['Authorization'] = store.getters.authToken
}
return config
}
//Token handling
axios.interceptors.request.use(config => tokenHandler(config, store), errorHandler.bind(ctx))
Now I do not need to use setToken at all and it workds both server and client side.
I will try to fork a repo and make a PR.
from axios-module.
Awesome solution. Where is the store passed in from and which store instance is this?
But man handling axios is pretty scary. I would have thought axios is segmented as long as you use axios provided in the context.
from axios-module.
from axios-module.
[2] After $axios.setToken on the server side, the $axios instance loses token on the client side.
Same thing here, what is solution?
@TheDeveloperTom @supertino7 @uptownhr @pi0
from axios-module.
same thing here, is there any beforeRequest
method to set token before sending a request?
from axios-module.
IMPORTANT.
UPDATE:
This solution will APPEAR to work, but only makes the problem less visible. I.e. I simply do not know what Nuxt 'Does' on a new request - i suspect it will not 'reimport' anything - so by setting a module variable i just have another global that will not be correct.
I can see NO way expect passing the / using the $axios instance and passing it to the point where it is needed... (i.e. pages, vuex stores) but no longer 'clean' service files.
Sorry...
Note there is nothing wrong with nuxtjs/axios just the hack i use
I updated to Nuxt 2.4.0 and i saw some pretty strange behaviour from the code i posted before:.
import axios from "Axios"
export default (context) => {
//store is the current store, both server and client side. and unique for nuxtServerInit
let {store, app} = context;
axios.interceptors.request.use(config => tokenHandler(config, store),
function (error) {
return Promise.reject(error);
});
}
This causes the request handler to be ADDED for each time a full SSR page is rendered. This means you might 'phantom' tokens.
I do not know if this was the case in pre 2.4.0 - but i suspect it was also doing this.
I now use @nuxtjs/axios . I looked at the code and noticed the issues (about re-using the axios 'global').
However i didn't want to change my whole code (i.e. my JWT is stored in the store, so 'reactive').
so my code is now:
nuxt.config.js:
modules: [
'@nuxtjs/axios',
],
plugins: [
'@/plugins/axios',
],
And plugins/axios.js (so both server / client in the new plugin way for 2.4)
function tokenHandler(config, store) {
if (store.state.account.user && store.state.account.user.jwt) {
//we could just use $axios.setToken
config.headers.common['Authorization'] = `Bearer ${store.state.account.user.jwt}`;
}
return config
}
//https://github.com/nuxt-community/axios-module/issues/28
import { setAxiosInstance } from '~/services/http'
export default ({ app, store }) => {
let axiosInstance = app.$axios;
//install the INSTANCE based handler. So each request this will be called
axiosInstance.onRequest(config => tokenHandler(config, store));
setAxiosInstance(axiosInstance);
}
then my services/http.js - this used to be a simple
'import axios from axios'.
is now:
//NOTE: NO import axios.
let axiosInstance = null;
export function setAxiosInstance(instance) {
axiosInstance = instance;
axiosInstance.defaults.baseURL = API_ROOT;
}
//rest of code now uses axiosInstance where axios used to be.
Nothing else needed to change, and my code isn't clobbered by $axios. statements still .
from axios-module.
I'm pretty lost. :'( What is the recommended way of setting the token now? When I set it on the server side only, its lost in the client side.
from axios-module.
My app will eventually use a federated authentication system (passport-cas) that isn't and will probably never be one of the ones supported by auth-module.
from axios-module.
My app will eventually use a federated authentication system (passport-cas) that isn't and will probably never be one of the ones supported by auth-module.
Indeed https://auth.nuxtjs.org will be used by most but more traditional auth methods (enterprise) it doesn't do.
from axios-module.
Do we have a recommended way to pass authorization header by default? I used awronski example here #298 (comment) but on server side I dont see authorization header at all. log in/log out work with auth middleware, but when I initiate axios.get myself, authorization header is not attached.
from axios-module.
@m4tty-d I don't know what the recommended way but I am using this with success:
plugins/axios.js:
export default function ({ $axios, app, store }) { $axios.onRequest(config => { if (store.state.authToken) { config.headers.common['Authorization'] = store.state.authToken } }) }
Using nuxt v2.14.6
.
Can setToken
work with a privateRuntimeConfig
setting? I'm trying to send a bearer authorization token that is stored in my .env
and read into:
privateRuntimeConfig: {
apiToken: process.env.API_TOKEN
}
I tried to test the interceptor plugin approach like so:
export default function ({ $config: { apiToken }, $axios }) {
$axios.onRequest((config) => {
console.log(apiToken)
})
}
and in my console I see 2 logs: one underneath Nuxt SSR
that shows the correct value and then undefined
. I'm making a this.$axios.$get
call in a page file created()
method. Because of the undefined
, I get an error returned from the 3rd party API saying the token is missing.
UPDATE
I didn't realize certain areas (asyncData, plugins, created() method, etc.) run twice, once on the server-side and another time client-side. So the first time they run the server has access to privateRuntimeConfig
, but the second time the client does not. So when I try to set the bearer auth token in a plugin, it works when server-side, but then immediately gets set to undefined
on the second run client-side. I'm not sure what to do with this information hah. Can I wrap the interceptor request in the plugin file with a check for process.server
so it only runs on the server?
from axios-module.
Can I wrap the interceptor request in the plugin file with a check for process.server so it only runs on the server?
@cswkim
This solution does not works in your case. You need to set valid token in client side as well as server. Setting token on one of them does not affect axios instance on another.
In other words, you should use publicRuntimeConfig
.
from axios-module.
Related Issues (20)
- Problem with ssr Cors then axios and proxy
- filename.split error on nuxt generate and ssr HOT 2
- dont work on nuxt rc.6
- Cannot send cookies through server side
- Update to latest axios HOT 5
- Export `NuxtAxiosInstance` typings HOT 3
- Why does nuxtjs/axios trigger options requests
- diferrent url in nuxt 3
- Nuxt 3: Cannot start nuxt: Cannot read properties of undefined (reading 'options') HOT 3
- Nuxt3, how to fix this error HOT 2
- [Nuxt 2] defu__WEBPACK_IMPORTED_MODULE_3__ is not a function
- Is this repo still maintained & any plans to upgrade to axios v1.* ? HOT 2
- Status code is not returned for 413 responses HOT 1
- Last part of url getting removed during request
- Cannot restart nuxt: Cannot read properties of undefined (reading 'options') HOT 1
- nuxt/axios this.$axios.get() options doesn't seem to work
- Authorization header is not being set with Auth Module cookie strategy
- Release with latest axios HOT 1
- node_modules\vue-server-renderer\build.dev.js
- Security issue: Uses a vulnerable version of Axios
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from axios-module.