axios-module
axios-module copied to clipboard
axios module: axios.setToken where to run?
I am currently running this in nuxtServerInit if a token is available. Progressing a little further, I noticed that the token is no longer available from the client. Meaning I also need to run setToken
again from the client side. From which nuxt lifecycle stage should I set the token with $axios.setToken?
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.
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)
}
I tried to provide a solution that did not know if it was feasible.
@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?
@pi0 Sorry, just did not pay attention to see you on a comment, really perfect solution to this problem.
@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?
Also what is the difference between accessing $axios from the context vs grabbing from ctx.app
@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 )
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')
}
Yes you do have to set on both. I'd break down your get cookie logic with isserver and isclient
On Fri, Jul 28, 2017, 4:40 AM awronski [email protected] wrote:
Hello @pi0 https://github.com/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') }
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nuxt-community/modules/issues/89#issuecomment-318630677, or mute the thread https://github.com/notifications/unsubscribe-auth/AA-Utrxzodzhv7pZ_pZox2_s43fPLHJqks5sScijgaJpZM4Oh9dS .
@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 by any chance is there a sample code to also inject axios into the vuex action dispatcher?
On Fri, Jul 28, 2017, 9:55 AM Pooya Parsa [email protected] wrote:
@awronski https://github.com/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 :)
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nuxt-community/modules/issues/89#issuecomment-318706713, or mute the thread https://github.com/notifications/unsubscribe-auth/AA-UtnrKbrwsUSvFXRmBvZSbKs9NBmbLks5sShKQgaJpZM4Oh9dS .
@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.
I don't think you want to use defaults. That affects it globally. The axios module has a set token method avail for you to use.
On Fri, Jul 28, 2017, 10:54 AM awronski [email protected] wrote:
@pi https://github.com/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.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nuxt-community/modules/issues/89#issuecomment-318721089, or mute the thread https://github.com/notifications/unsubscribe-auth/AA-UtqS3VMf4z92rDbqQ6QiOP2gwtV9Kks5sSiBogaJpZM4Oh9dS .
@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.
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')
}
@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.
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.
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.
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
Thank you!
On Sun, Aug 13, 2017, 7:41 AM Pooya Parsa [email protected] wrote:
Axios module has a new home https://github.com/nuxt-community/axios-module and finally, SSR is safe to use setToken and setHeader. The main cause was totally crazy! commit https://github.com/nuxt-community/axios-module/commit/935522853674bd986380eb754b532da2dc94dcc7 . Upgrade to >= 3.1.3 is recommended for everyone!
yarn add @nuxtjs/axios@^3.1.3# or npm i @nuxtjs/axios@^3.1.3
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/nuxt-community/modules/issues/89#issuecomment-322046142, or mute the thread https://github.com/notifications/unsubscribe-auth/AA-UtjqmaqFmHR6TjUk65PYwRWFgyH1sks5sXwsZgaJpZM4Oh9dS .
@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.
@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?
Same thing here, I do a this.$axios.setToken(token, 'Bearer')
in nuxtServerInit() then the authorization header disappears on client side :(
[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
same thing here, is there any beforeRequest
method to set token before sending a request?
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..
@opgbaudouin thanks a lot for this. Searched for two hours how to do this.
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 .
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.