I'm muddling my way through implementing JWT authentication in a new Vue app and am running into an issue. I'm working off of the webpack CLI template FWIW.
In my main.js I have the following code after declaring my Vue app:
window.axios = axios
window.axios.defaults.baseURL = 'https://example.com'
if (localStorage.getItem('token') !== null) {
window.axios.defaults.headers.common['authorization'] = 'Token ' +
localStorage.token
}
Vue.router = router
This works fine when I log in, however after I'm redirected post-login (/sign-up) and then navigate to a new page (/sign-up/inventory) I try the following axios call and get a 404 because the baseURL can no longer be found.
axios.get('myapi/myreport/mydata/').then(function (response) {
console.log(response)
})
.catch(e => {
console.log(e)
})
}
If I log window.axios.defaults.baseURL just prior to the axios call I get an error ("Cannot read property 'defaults' of undefined") so presumably axios isn't even loading? What should I be checking in order to trouble-shoot this?
I moved the axios code up up above my app instantiation on main.js and that seems to have fixed it.
Related
I'm new to the node world and I'm having issues setting up my Nuxt3 project to use Apollo, but I think most of it is lack of knowledge with node and Nuxt.
Everything works fine when the setup code is in app.vue but I want it in a separate file to keep things tidy.
This is my latest attempt, I also tried using /server/api to return values, but I ran into top-level await issues.
I created a Stack Blitz instance to show what's happening. It renders successfully once, then shows an undefined error underneath. In my project, it's similar in a way where I see a flash of content, and then an empty white page and a console error that spaceId is undefined (braking the url).
plugins/apollo.ts
import { ApolloClient,createHttpLink,InMemoryCache} from '#apollo/client/core';
import { createApp, provide, h } from 'vue';
import { DefaultApolloClient,provideApolloClient} from '#vue/apollo-composable';
export default defineNuxtPlugin(async (nuxtApp) => {
const config = useRuntimeConfig();
const httpLink = createHttpLink({
uri: `https://someapi/${config.spaceID}/`,
headers: {
Authorization: `Bearer ${config.token}`,
},
});
// Cache implementation
const cache = new InMemoryCache();
// Create the apollo client
const apolloClient = new ApolloClient({
link: httpLink,
cache,
});
provideApolloClient(apolloClient);
});
Thanks
Im looking to use $auth inside my Nuxt project, specially inside an axios plugin.
Here is my code:
plugins/api.js
export default function ({ $axios }, inject) {
const api = $axios.create({
headers: {
common: {
Accept: 'text/plain, */*',
},
},
})
// Set baseURL to something different
api.setBaseURL('http://localhost:4100/')
// Inject to context as $api
inject('api', api)
}
Now the problem comes when I try to use $auth from #nuxtjs/auth-next package.
As stated in the docs:
This module globally injects $auth instance, meaning that you can
access it anywhere using this.$auth. For plugins, asyncData, fetch,
nuxtServerInit and Middleware, you can access it from context.$auth.
I tried the following:
This results in $auth being undefined
export default function ({ $axios, $auth }, inject) {
This one was near
export default function ({ $axios, app }, inject) {
console.log(app) //This one logs $auth in the object logged
console.log(app.$auth) // I don't understand why but this one returns undefined
My main goal here is to make use of this.$auth.strategy.token.get()and pass it (if the token exists of course) to the headers of every request made using this.$api
I have been looking for similar questions and answers but none has helped me to solve this, I could just add the token every time I write this.$api but that would increase the code unnecessarily.
Thanks in advance to all the people for your time and help.
EDIT:
Okay, now I made a test. and the next code is actually logging the $auth object correctly, it seems some time is needed to make it work but now Im afraid that using setTimeout could cause an error because I can't know exactly how much time is needed for $auth to be available.
export default function ({ $axios, app }, inject) {
setTimeout(() => {
console.log('After timeout', app.$auth)
}, 50)
EDIT 2:
So now I have made more tests, and using 0 milliseconds instead of 50 works too, so I will use setTimeout with 0 milliseconds for now, I hope anyone find a better solution or explain why $auth is not available before using setTimeout so I can decide what to do with my code.
EDIT 3:
After trying to wrap all my previous code inside setTimeout I noticed that the code fails, so that isn't a solution.
I have found a solution so I will post it so that every person that could have the same problem in the future can solve it.
It turns out that I could easily solve it using interceptors.
export default function ({ $axios, app }, inject) {
// At this point app.$auth is undefined. (Unless you use setTimeout but that is not a solution)
//Create axios instance
const api = $axios.create({
headers: {
common: {
Accept: 'application/json', //accept json
},
},
})
// Here is the magic, onRequest is an interceptor, so every request made will go trough this, and then we try to access app.$auth inside it, it is defined
api.onRequest((config) => {
// Here we check if user is logged in
if (app.$auth.loggedIn) {
// If the user is logged in we can now get the token, we get something like `Bearer yourTokenJ9F0JFODJ` but we only need the string without the word **Bearer**, So we split the string using the space as a separator and we access the second position of the array **[1]**
const token = app.$auth.strategy.token.get().split(' ')[1]
api.setToken(token, 'Bearer') // Here we specify the token and now it works!!
}
})
// Set baseURL to something different
api.setBaseURL('http://localhost:4100/')
// Inject to context as $api
inject('api', api)
}
Also Nuxt Auth itself has provided a solution for this issue:
https://auth.nuxtjs.org/recipes/extend/
I have a site which makes an Axios request. Both the backend and vuejs frontend are on the same domain, and have the same basic auth covering them.
The issue is that whilst the pages load, as soon as an Axios request is made, it asks me again for the basic auth, which doesn't even work if I fill in the details.
Now I imagine I need to pass through the basic auth details somehow, but none of the things I have tried work (and example being below).
If anyone has any tips on passing through the auth token from the parent page to the axios request, that would be great.
const requestOne = axios.get(requestUrl)
const requestTwo = axios.get(requestUrl)
axios
.all([requestOne, requestTwo])
.then(
axios.spread((...responses) => {
<some code here>
})
)
I just answered a similar question with the 3 ways to pass around data in Vue.
You might find it helpful: How to pass v-for index to other components
However, in my opinion, the best approach would be to create a Vue plugin with your Axios client and an init method.
Consider this following (untested) example:
axiosClient.js
import Vue from 'vue';
let instance;
export const getInstance = () => instance;
export const useAxios = () => {
if (instance) return instance;
instance = new Vue({
data() {
return {
client: null,
}
}
});
methods: {
init(authToken) {
this.client = axios.create({
headers: {'Authorization': authToken }
});
}
}
}
export const axiosPlugin = {
install(Vue) {
Vue.prototype.$axios = useAxios();
},
};
Vue.use(axiosPlugin);
Once installed, you can access this in your components using $axios.init(...) and $axios.client.
You can even write API methods directly onto the plugin as well and interact with Vuex through the plugin!
You may need to tweak the plugin a little (and keep in mind this is Vue2 syntax) as I wrote this directly into StackOverflow.
You can also pass any other default values or configuration options through to the axios client by providing options to the plugin and accessing them within init.
You can learn more about plugins here: https://v2.vuejs.org/v2/guide/plugins.html
I have deployed a Vue.js application to heroku an api also hosted on heroku.
The VueJS app uses axios to connect to the api. I have set a config variable in heroku:
VUE_APP_ROOT_API = https://[my-express-api].herokuapp.com/api
Here is my base axios call:
import axios from 'axios'
const token = localStorage.getItem('token')
export default () => {
console.log(process.env.VUE_APP_ROOT_API)
return axios.create({
baseURL: process.env.VUE_APP_ROOT_API,
headers: {
'Content-Type': 'application/json',
token: token,
},
validateStatus: function () {
return true;
}
})
}
However, the console log reveals that the variable is undefined and axios is using the Vue app url as the base for api calls (https://[my-vue-app].herokuapp.com/undefined/) instead of the one specified in the config variable.
Resolved this. It turns out that my config variable was being compiled into the code at build time, so once I deployed to trigger a rebuild, the new config var worked. Adding/Updating config vars will automatically restart the dynos, but that doesn't rebuild any compiled code.
For me, appending the build command in my package.json with '--mode production' before pushing to heroku fixed the issue.
https://forum.vuejs.org/t/production-env-on-app-deployed-in-heroku/71077
Good luck!
I have a method to call a login endpoint on a button click
login() {
let email = this.user.email
let password = this.user.password
axios.post('invalidRoute').then( (response) =>{
console.log('success')
console.log(response.data)
}).catch(function (error) {
console.log('error')
console.log(error)
})
},
No matter what I set as the url route, axios thinks that the post is successful and always logs out the success message and a blank response data.
I import axios directly at the top of the component using the line
import axios from 'axios'
I don't use it anyhere else.
This is in a basic nativescript vue js application.
this is what my main.js looks like
import Vue from "nativescript-vue";
import Vuex from 'vuex'
import store from './store/store';
import * as applicationSettings from 'tns-core-modules/application-settings'
import router from './router'
Vue.prototype.$router = router
Vue.config.silent = false
Vue.use(Vuex)
new Vue({
render: h => h('frame', [h(router['login'])]), store
}).$start()
It is driving me nuts, I cant see why it won't trigger the catch.
I think it's an issue with Axios. With {N} status code will be null when request fails, seems Axios considers that request as success when the status code has falsy value.
Looks like there is a similar issue logged in their Github.
I found that axios nor http doesn't call anything in some circumstances.
I don't know why, i was investigated this for two days. No clue.
Just used Fetch instead and for now everything works fine.