I'm trying to implement authentication in vuejs 3. I'm django and django as a backend and simple jwt for generating token. Every things is working fine. Generated token are in this format.
And here is my auth store , by the way I'm using axios and vuex
import axios from "axios";
import { API_ENDPOINTS } from "../../constants/API";
const authStore = {
state: {
status: "",
access_token: localStorage.getItem("access_token") || "",
refresh_token: localStorage.getItem("refresh_token") || "",
},
mutations: {
auth_request(state) {
state.status = "loading";
},
auth_success(state, access_token, refresh_token, user) {
state.status = "success";
state.access_token = access_token;
state.refresh_token = refresh_token;
state.user = user;
},
auth_error(state) {
state.status = "error";
},
logout(state) {
state.status = "";
state.access_token = "";
state.refresh_token = "";
},
},
actions: {
login({ commit }, user) {
return new Promise((resolve, reject) => {
commit("auth_request");
axios({
url: API_ENDPOINTS.CREATE_TOKEN,
data: user,
method: "POST",
})
.then((resp) => {
console.log(resp);
const access_token = resp.data.access;
const refresh_token = resp.data.refresh;
const user = resp.data.user;
localStorage.setItem("access_token", access_token);
localStorage.setItem("refresh_token", refresh_token);
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${access_token}`;
commit("auth_success", access_token, refresh_token, user);
resolve(resp);
})
.catch((err) => {
commit("auth_error");
localStorage.removeItem("access_token");
localStorage.removeItem("refresh_token");
reject(err);
});
});
},
logout({ commit }) {
// eslint-disable-next-line no-unused-vars
return new Promise((resolve, reject) => {
commit("logout");
localStorage.removeItem("access_token");
localStorage.removeItem("refresh_token");
delete axios.defaults.headers.common["Authorization"];
resolve();
});
},
},
getters: {
isLoggedIn: (state) => !!state.access_token,
authStatus: (state) => state.status,
},
};
export default authStore;
Above code is working fine, only issue is that whenever I refresh my page, I can't able to perform any operation, Like get or post.
Even token is available in localstorage.
Note:-
I think I'm missing some things like refresh token, I think i need to use refresh token, but I've no any idea that how can i use refresh token if refresh token is problem.
axios.defaults.headers.common[
"Authorization"
] = `Bearer ${access_token}`;
This code is noly called when user login, so maybe you should call it when the token is availble at localstorage.
Related
here is my code I use Vue 3 and pinia my store is and after login, I save the token in local storage, and on logout I remove the item but the problem is the remove action didn't work till I refresh the page or till some minute
actions: {
async login(token, userId, currentUser) {
this.currentUser = currentUser;
window.localStorage.setItem("token", token);
},
async logout() {
localStorage.clear();
sessionStorage.clear();
this.isLoggedIn = false;
this.router.push({ name: "signin" });
apolloClient.cache.data.clear();
},
async addFoods(...foods) {
this.foods = foods;
},
},
persist: {
enabled: true,
},
and my apollo request header is
const token = window.localStorage.getItem("token");
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
...((token && { authorization: `Bearer ${token}` }) || ""),
},
};
});
export const apolloClient = new ApolloClient({
cache,
link: authLink.concat(httpLink),
});
I have a problem to save JWT Token in Local Storage (or cookie). Now, when I refresh my page, I need to login again. When I POST to /api-token with username and password in response I've got access token and refresh token, and now, don't now how to store them and where.
My loginForm.vue:
(<form...)
<script>
import axios from 'axios';
export default {
name: 'LoginForm',
data(){
return{
username: '',
password: '',
}
},
methods: {
login(){
this.$store.dispatch('userLogin', {
username: this.username,
password: this.password
})
.then(() => {
this.$router.push({ name: 'home'})
})
.catch(err => {
console.log(err)
})
}
}
}
</script>
and my store.js:
import Vue from 'vue'
import Vuex from 'vuex'
import { getAPI } from './api'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
accessToken: null,
refreshToken: null,
},
mutations: {
updateStorage (state, { access, refresh }) {
state.accessToken = access
state.refreshToken = refresh
},
destroyToken (state) {
state.accessToken = null
state.refreshToken = null
}
},
getters: {
loggedIn (state) {
return state.accessToken != null
}
},
actions: {
userLogin (context, usercredentials){
return new Promise((resolve, reject) => {
getAPI.post('/api-token/', {
username: usercredentials.username,
password: usercredentials.password
})
.then(response => {
context.commit('updateStorage', {access: response.data.access, refresh: response.data.refresh})
resolve()
})
})
},
userLogout (context) {
if (context.getters.loggedIn) {
context.commit('destroyToken')
}
}
}
})
I'm assuming I need to save them in local storage by store.js, after update and before destroy. Could you help me?
You need something like this:
You must save access token in default header's requests to auth user after every requests . also save token in localstorage:
axios.post('login', this.user)
.then(r=>
{
axios.defaults.headers.common['Authorization'] = 'Bearer ' + r.data.token;
localStorage.setItem( 'token', JSON.stringify(r.data.token) );
}
and add to default headers on refresh: (top of main.js file)
let token = JSON.parse( localStorage.getItem('token') );
if( token ){
window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
}
now you can send request from every component
in the login page in (script) tag add this code
axios.post('/api/v1/token/login/', this.form)
.then((r) => {
axios.defaults.headers.common['Authorization']='Bearer'+r.data.auth_token;
localStorage.setItem('token', JSON.stringify(r.data.auth_token));
})
and in the main.js add
let token = JSON.parse( localStorage.getItem('token') );
if( token ){
window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + token;
}
I am taking data from api, how to send get request with token after login?
It shows error createError.js?2d83:16 Uncaught (in promise) Error: Request failed with status code 401
export default new Vuex.Store({
state: {
users: []
},
mutations: {
setUsers(state, args){
state.users = args;
}
},
actions: {
login({ }, arg) {
axios.post('login/', { username: arg.username, password: arg.password })
.then((response) => {
console.log(response);
let accessToken = response.token.data;
localStorage.setItem('token', accessToken);
localStorage.setItem('user', response.data.user);
axios.defaults.headers.common['Authorization'] = accessToken;
window.isSignedIn = true;
router.push('/');
})
.catch((error) => {
console.log(error);
})
},
getUsers({ commit }){
let { data } = axios.get('v1/user/list/');
commit('setUsers', data);
}
}
})
Depends which authentication you are using. Try with:
axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;
Other HTTP authentication schemes.
I'm trying to get this informations and put it in "user" :
the action in VueJS:
export default new Vuex.Store({
state: {
status: '',
token: localStorage.getItem('token') || '',
user : {},
test : []
},
mutations: {
auth_request(state){
state.status = 'loading'
},
auth_success(state, token, user){
state.status = 'success'
state.token = token
state.user = user
},
auth_error(state){
state.status = 'error'
},
logout(state){
state.status = ''
state.token = ''
},
},
actions: {
login({commit}, user){
return new Promise((resolve, reject) => {
commit('auth_request')
axios.get('http://localhost:8080/offreeduwar/api/Useraccount/login/'+ user.email+'/'+user.password)
.then((resp) => {
const token = resp.data.token
const user = resp.data
console.log(test)
localStorage.setItem('token', token)
// Add the following line:
axios.defaults.headers.common['Authorization'] = token
commit('auth_success', token, user)
resolve(resp)
})
.catch(err => {
commit('auth_error')
localStorage.removeItem('token')
reject(err)
})
})
},
But all the time in Vue devtool : the state of user is empty , so the question how to put this informations in user to work with this variable
The commit method in the store has two parameters: the name of the mutation and the params (if it is of a primitive type, the value itself, if it is an object, then an object). So you should try it like this:
commit('auth_success', { token, user })
and then:
auth_success(state, payload){
state.status = 'success'
state.token = payload.token
state.user = payload.user
},
I have a simple vue app where I'm trying to add simple authentication. Inside my login.vue, I use axios to authenticate the user via ajax and store the token returned by the api in the store then redirect to a new page (ex: dashboard.vue).
The problem is that the token is saved but the view is not updated, can't call router.push() ...
Any ideas why isn't it working ? Thanks
Login.vue
methods: {
authenticate () {
var dataLogin = {
email: this.login,
password: this.password
}
var headers = { headers: { 'Content-type': 'application/json', 'Accept': 'application/json' } }
axios.post(config.apiUrl, dataLogin, headers)
.then(response => {
this.$store.dispatch('login', response.data).then(() => {
// if there is no error go to home page
if (!this.$store.getters.error) {
this.$router.push('/')
}
})
})
.catch(error => {
this.errorMessage = error.response.data.message
this.authError = true
})
}
}
The store function just save the token with localStorage
const actions = {
login (context, data) {
context.commit('authenticate', data)
}
}
const mutations = {
authenticate (state, data) {
localStorage.setItem('user-access_token', data.access_token)
}
}
You are calling a then() handler when you dispatch the action.
But your action does not return a promise.
So return a promise in your action as follows:
const actions = {
login (context, data) {
return new Promise((resolve, reject) => {
context.commit('authenticate', data)
resolve()
})
}
}
Also chain your promises for better readability
axios.post(config.apiUrl, dataLogin, headers)
.then(response => {
return this.$store.dispatch('login', response.data)
}).then(() => {
// if there is no error go to home page
if (!this.$store.getters.error) {
this.$router.push('/')
}
})
.catch(error => {
this.errorMessage = error.response.data.message
this.authError = true
})