Where can i put the Authorization header token in axios after dispatching login action with laravel passport authentication in a seprated vue.js project?I tried with setting it in main.js like this and doesnt work properly. After dispatching, In the QuestionIndex component, the axios call dont have the authorization header automatically. And by refreshing the page, it has the authorization header. I can fix this by putting the token header in QuestionIndex Component. But I dont think this is a proper way to do it. Please help me with this problem.
In main.js
const token = localStorage.getItem('access_token');
if (token) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
}
In login.vue
login(){
this.$store
.dispatch("login", this.form)
.then(() => {
this.$router.push({ name: "QuestionIndex" });
})
.catch(err => {
console.log(err);
});
}
In vuex store
state: {
token: localStorage.getItem('access_token') || null,
user: {},
},
mutations: {
setToken(state, data) {
state.token = data.token;
state.user = data.user;
},
},
actions: {
login({ commit }, credentials) {
return axios.post("http://127.0.0.1:8000/api/login", credentials).then(( res ) => {
localStorage.setItem('access_token', res.data.data.token);
commit("setToken", res.data.data);
});
},
},
getters: {
token: (state) => state.token,
}
You can set the Authorization header after initializing the axios instance like this:
axiosInstance.interceptors.request.use((config) => {
const token = localStorage.getItem('access_token');
config.headers.Authorization = `Bearer ${token}`
return config
})
In your VUEX action, make sure to use the axiosInstance you created in your main.js (or whereever). If you just import axios in your VUEX store like this import axios from 'axios' it will not work, because it's not the axios instance you set the header on.
you can try this
axios.post("http://127.0.0.1:8000/api/login", credentials, { headers: { Authorization: 'Bearer ' + localStorage.getItem('access_token') } })
Related
I'm backend guy who wants to gain some Vue.js skills. In my app I've got Ruby on Rails as backend and Vue.js as front-end with a standard JWT token flow. I'm trying to send a POST request (fetchAllProductsRequest) to the backend that will trigger some background job using below code:
index.js
const fetchAllProductsRequest = (self) => {
const jwtToken = self.$store.state.idToken;
return axios
.post(`/api/v1/imports/products/fetch_all`,{
headers: {
Authorization: `Bearer ${jwtToken}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(response => response.data)
};
Quite surprisingly I get an error: Request failed with status code 401. When I debugging it on the backend side I see that I send an empty token inside the header:
[1] pry(#<Api::V1::Imports::ProductsController>)> params[:headers]
=> #<ActionController::Parameters {"Authorization"=>"Bearer null", "Content-Type"=>"application/json", "Accept"=>"application/json"} permitted: false>
Here is a function that triggers fetchAllProductsRequest which is responsible for POST request:
fetch_all.vue
<script>
import {
fetchAllProductsRequest,
} from '../../api/imports'
import ModalController from '../general/modal_controller'
export default {
name: 'BackboneFetchAll',
data() {
return { }
},
components: {
MoonLoader
},
computed: {
databaseSyncInProgress() {
return this.$store.getters.getDatabaseSyncStatus;
},
},
methods: {
async syncAll() {
let confirmationText = `Do you want to sync all Backbone products?`
if (await ModalController.showConfirmation('Confirmation', confirmationText)) {
try {
ModalController.showLoader()
await fetchAllProductsRequest(this)
this.$store.commit('setSyncingProductsInProgress', value)
const successMessage = `Database synchronization has been queued`
await ModalController.showToast('', successMessage)
} catch (data) {
const errorMessage = `Error occurred during queueing products to sync - `
ModalController.showToast('', errorMessage + data?.message, 'error')
} finally {
ModalController.hideLoader()
}
}
},
}
}
</script>
What did I missed?
I am writing code to call api using axios. So, for this code I have to send an otp to the api along with an authorization token. I am using vuex store.
I am getting an error of 406(not applicable). This is the code I have written.
import { isAuthenticated } from './auth'
import axios from 'axios'
export default ({
state: {
},
mutations: {
},
getters: {
},
actions: {
VERIFY: (payload) => {
const userId = isAuthenticated().user._id
return axios
.post(apilink, payload, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${isAuthenticated().token}`,
Accept: 'application/json'
}
}).then(response => {
console.log(response)
return response.data
})
.catch(error => {
if (error) {
console.log(error)
}
})
}
},
modules: {
}
})
<template>
<mdb-btn color="info" #click="verify()">Verify</mdb-btn>
</template>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js">
data () {
return {
value: ''
}
},
methods: {
verify () {
this.$store.dispatch('VERIFY', {
otp: this.value
}).then(success => {
console.log(success)
}).catch(error => {
console.log(error)
})
}
}
</script>
I think it's the problem with authorization part. Please help me.
isAuthenticated is funtion used to get data from localStorage
export const isAuthenticated = () => {
if (localStorage.getItem('auth')) {
return JSON.parse(localStorage.getItem('auth'))
}
return false
}
406 error is appearing because of Accept parameter in the header try after removing "Accept: 'application/json'"
I'm setting a basic authentication on a Nuxt project with JWT token and cookies to be parsed by nuxtServerInit function.
On login with email/password, works as intended, setUser mutation is triggered and the appropriate user object is stored in state.auth.user.
On reload, nuxtServerInit will get the jwt token from req.headers.cookies, call the GET method and identify user.Works like a charm.
Problem starts when I hit the /logout endpoint. state.auth.user is set to false and Im effectively logged out... but If I refresh, I'm logged in again with the previous user data. Even if my cookies are properly empty (on below code, both user and cookie are undefined after logout and refresh, as expected)
So I really don't get why is my state.auth.user is back to its initial value...
store/index.js
import Vuex from "vuex";
import auth from "./modules/auth";
import axios from "~/plugins/axios";
const cookieparser = process.server ? require("cookieparser") : undefined;
const END_POINT = "api/users";
const createStore = () => {
return new Vuex.Store({
actions: {
async nuxtServerInit({ commit, dispatch}, { req }) {
let cookie = null;
console.log(req.headers.cookie)
if (req.headers.cookie) {
const parsed = cookieparser.parse(req.headers.cookie);
try {
cookie = JSON.parse(parsed.auth);
console.log("cookie", cookie)
const {accessToken} = cookie
const config = {
headers: {
Authorization: `Bearer ${accessToken}`
}
}
const response = await axios.get(`${END_POINT}/current`, config)
const user = response.data
console.log("user nuxt server init", user)
await commit('setUser', user)
} catch (err) {
// No valid cookie found
console.log(err);
}
}
}
},
modules: {
auth
}
});
};
export default createStore;
modules/auth.js
import axios from "~/plugins/axios";
const Cookie = process.client ? require("js-cookie") : undefined;
const END_POINT = "api/users";
export default {
state: {
user: null,
errors: {}
},
getters: {
isAuth: state => !!state.user
},
actions: {
login({ commit }, payload) {
axios
.post(`${END_POINT}/login`, payload)
.then(({ data }) => {
const { user, accessToken } = data;
const auth = { accessToken };
Cookie.set("auth", auth);
commit("setUser", user);
})
.catch(e => {
const error = e;
console.log(e);
commit("setError", error);
});
},
logout({ commit }) {
axios
.post(`${END_POINT}/logout`)
.then(({ data }) => {
Cookie.remove("auth");
commit("setUser", false);
})
.catch(e => console.log(e));
},
},
mutations: {
setUser(state, user) {
state.user = user;
},
setError(state, errors) {
state.errors = errors;
}
}
};
The way I logout my user is by creating a mutation called clearToken and commit to it in the action :
State :
token: null,
Mutations :
clearToken(state) {
state.token = null
},
Actions :
logout(context) {
context.commit('clearToken')
Cookie.remove('token')
}
This way, you token state revert back to null.
I want to use axios interceptor before every axios call to pass idToken as authorization header with all the axios calls and I want to refresh the idToken if it has expired before any call.
I am using the following code:
axios.interceptors.request.use(function(config) {
var idToken = getIdToken()
var refreshToken = {
"refreshToken" : getRefreshToken()
}
if(isTokenExpired(idToken)){
console.log("==============Reloading")
refresh(refreshToken).then(response=>{
setIdToken(response.idToken)
setAccessToken(response.accessToken)
})
idToken = getIdToken()
config.headers.Authorization = `${idToken}`;
}
else{
config.headers.Authorization = `${idToken}`;
}
return config;
}, function(err) {
return Promise.reject(err);
});
It works fine till the time idToken is valid. When the idToken expires it gets in an infinite loop and the page hangs. Please help me with this. The refresh() which call the refresh API looks like this:
function refresh(refreshToken) {
const url = `${BASE_URL}/user/refresh`;
return axios.post(url,JSON.stringify(refreshToken))
.then(response =>response.data.data)
.catch(e => {
console.log(e);
});
}
I had some similar problem and creating new axios instance to perform refresh token api call resolved the problem (new AXIOS instance is not resolved by defined axios.interceptors.request.use) (of course below code is just a simple example).
Remember to save original request and process it after token has been refreshed:
F.ex my http-common.js
import axios from 'axios'
const AXIOS = axios.create()
export default AXIOS
...
in App.vue:
axios.interceptors.request.use((config) => {
let originalRequest = config
if (helper.isTokenExpired(this.$store.getters.tokenInfo)) {
return this.refreshToken(this.$store.getters.jwt).then((response) => {
localStorage.setItem('token', response.data.token)
originalRequest.headers.Authorization = response.data.token
return Promise.resolve(originalRequest)
})
}
return config
}, (err) => {
return Promise.reject(err)
})
and the refresh token method:
refreshToken (token) {
const payload = {
token: token
}
const headers = {
'Content-Type': 'application/json'
}
return new Promise((resolve, reject) => {
return AXIOS.post('/api/auth/token/refresh/', payload, { headers: headers }).then((response) => {
resolve(response)
}).catch((error) => {
reject(error)
})
})
}
}
I'm working on a test-app with vuejs and vuex. I can signup/register the users and
I also got the user logged in and set the token in localstorage vuex. But where and how do you check if the user is already logged in after a refresh?
I'm currently using VUEX to handle async calls with axios.
the structure within my "store" folder is following
- Index.js
- actions.js
- mutations.js
- getters.js
Here is a part of my actions.js
import config from './../config'
import axios from 'axios'
import Ls from '../mixins/localStorage'
axios.defaults.headers.common = {
'Accept': 'application/json'
};
export default {
login ({commit,dispatch}, user) {
commit('setLoading', {
modalName: 'loginModal',
state: true
});
const endpoint = config.apiUrl + 'clients/web/login';
axios.post(endpoint, user)
.then(response => {
Ls.set('token',response.data.request_key);
dispatch('getUserData');
return true;
})
.catch(e => {
commit('setLoading', {
modalName: 'loginModal',
state: false
});
console.log(e);
return false
});
},
getUserData({commit}){
const endpoint = config.apiUrl + 'user/profile';
if(Ls.get('token')) {
axios.defaults.headers.common['Authorization'] = 'Bearer ' + Ls.get('token').replace(/(^\")|(\"$)/g, '');
}
axios.get(endpoint)
.then(response => {
commit('setUser',response.data);
commit('hideModal', 'loginModal');
})
.catch(e => {
console.log(e);
return false
});
}
}
So the question is
is this the right way to log a user in?
How and where do you check if the user is already logged in and if so, what do you do next ?
Thanks in advance!