i'm trying to integrate JWT authentication in my client using websanova.
My problem is that on every http request, library is setting token of the response body. Here is my app.js configuration
Vue.use(VueAxios, axios)
Vue.use(VueAuth, {
auth: {
request: function (req, token) {
req.headers['Authorization'] = 'JWT ' + token;
},
response: function (res) {
return res.data
}
},
http: require('#websanova/vue-auth/drivers/http/axios.1.x.js'),
router: require('#websanova/vue-auth/drivers/router/vue-router.2.x.js'),
loginData: { url: 'http://localhost:5005/api/authenticate', fetchUser: false },
fetchData: { enabled: false },
refreshData: { enabled: false },
authRedirect: { path: '/' }
})
And i handle login like this
login () {
this.$store.dispatch("login");
var redirect = this.$auth.redirect();
this.$auth.login({
headers: {
'Content-Type': 'application/json'
},
data: this.data.body,
rememberMe: this.data.rememberMe,
redirect: { name: redirect ? redirect.from.name : 'Home' },
fetchUser: false,
success (res) {
this.$store.dispatch("login_success");
},
err (err) { ...
Token is recived fine on login, but then when i want to display some table, token is overwriten by table source.
local storage before and after :
The problem is in your app.js configuration inside your auth-> response function.
PROBLEM
Vue.use(VueAxios, axios)
Vue.use(VueAuth, {
auth: {
request: function (req, token) {
req.headers['Authorization'] = 'JWT ' + token;
},
response: function (res) {
return res.data //HERE IS THE PROBLEM (You need to check the token and return it only when it is valid token)
}
},
http: require('#websanova/vue-auth/drivers/http/axios.1.x.js'),
router: require('#websanova/vue-auth/drivers/router/vue-router.2.x.js'),
loginData: { url: 'http://localhost:5005/api/authenticate', fetchUser: false },
fetchData: { enabled: false },
refreshData: { enabled: false },
authRedirect: { path: '/' }
})
SOLUTION
To solve it, you should check your token value res.data and then return it only if it is a valid token.
For example if the data return by the server after successfull authentication looks like {'token': '123ABC'} then your auth-> response function should look like this
Vue.use(VueAxios, axios)
Vue.use(VueAuth, {
auth: {
request: function (req, token) {
req.headers['Authorization'] = 'JWT ' + token;
},
response: function (res) {
//TEST IF DATA CONTAINS VALID AND RETURN IT.
if(res.data.token)
return res.data.token
//DON'T RETURN ANY VALUE IF THERE IS NO VALID TOKEN
}
},
http: require('#websanova/vue-auth/drivers/http/axios.1.x.js'),
router: require('#websanova/vue-auth/drivers/router/vue-router.2.x.js'),
loginData: { url: 'http://localhost:5005/api/authenticate', fetchUser: false },
fetchData: { enabled: false },
refreshData: { enabled: false },
authRedirect: { path: '/' }
})
For more information you visite this page: Vue-Auth custom auth drivers
Related
I have a problem with the authenticate with my Nuxt application (static SSR).
I'm using Sanctum. But the $auth variable is emptied after a refresh. So the user is disconnected.
login.vue
await axios.get(`${process.env.apiUrl}/sanctum/csrf-cookie`)
const res = await this.$auth.loginWith('laravelSanctum', {
data: {
email: this.userLogin.login.email,
password: this.userLogin.login.password,
}
})
.catch((error) => {
this.userLogin.messageError = 'Wrong credentials'
[ ... stop process code ...]
})
await this.$auth.$storage.setUniversal('_auth.user', JSON.stringify(res.data.user))
await this.$auth.setUser(res.data.user)
store/index.js
export const actions = {
async nuxtServerInit({ commit, dispatch }) {
const user = this.$auth.$storage.getUniversal('_auth.user')
if (user) {
await this.$auth.setUser(user)
}
}
}
nuxt.config.js
auth: {
strategies: {
laravelSanctum: {
provider: 'laravel/sanctum',
url: process.env.apiUrl,
endpoints: {
csrf: { url: '/sanctum/csrf-cookie', methods: 'GET' },
login: { url: '/api/login', method: 'POST' },
logout: { url: '/api/logout', method: 'POST' },
user: false
},
user: {
property: false,
autoFetch: false
},
cookie: false
}
},
redirect: {
login: '/mon-compte/login',
logout: '/mon-compte/login',
//home: '/mon-compte/mon-espace',
register: '/mon-compte/register'
}
}
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 an app which recieves token in my broswer url
http://localhost:8081/reset/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI2MmU2YWJmMmMzMzI0Mjk1NGQyNmVjZjIiLCJpYXQiOjE2NTk1MDIwNTEsImV4cCI6MTY1OTUwMjk1MX0.GIlKy_GI7HlfuB1WgD9HPxOGRZUX2_uOtOclrDTW3Y8
how can i remove (.) from my url
this is how i go to my route
{ name: "reset", path: "/reset/:token", component: Reset },
this is my script tag on how i call the function
<script>
import axios from "axios";
export default {
data() {
return {
password: "",
confirm_password: ""
};
},
mounted() {
console.log("the id is :" + this.$route.params.token);
},
methods: {
async submit() {
let token = this.$route.params.token;
let encoded = encodeURI(token);
return axios({
method: "post",
data: {
password: this.password,
token: this.$route.params.token
},
url: "http://localhost:5000/api/auth/updatePassword",
headers: {
"Content-Type": "application/json"
}
})
.then(res => {
console.log(res);
this.$router.push({ name: "login" });
})
.catch(error => {
console.log(error);
});
},
clear() {
this.$refs.form.reset();
}
}
};
</script>
i can't get the reset page until i remove the (.) please how can i encode the token
The token that you have is a JWT token, which should contain the two dots. I don't think removing them is a good idea. However, it looks like Vue router interprets the dots like a separator or something, causing the router to fail in finding the route.
What you might do is use a query string instead of a route param. You add the token to the url like:
http://localhost:8081/reset?token=eyJhbGciOiJ...
You should change the route to:
{ name: "reset", path: "/reset", component: Reset },
Now you can get it from the router with:
this.$route.query.token
I am using an index.js file to make api calls in a vue app. Is there a way to add a catch or a before each call to see if my token is still good and have the user redirected to login if it isnt?
import axios from 'axios'
const client = axios.create({
baseURL : 'http://myapi.com/api/',
json: true
})
export default {
async execute(method, resource, data) {
const token = localStorage.getItem('token')
return client({
method,
url: resource,
data,
crossdomain: true ,
headers: { "Authorization": `Bearer ${token}` }
}).then(req => {
return req.data
})
},
getResponses() {
return this.execute('get', 'GetResponses')
},
getAll(){
return this.execute('get', 'GetAll')
},
You can use an interceptor, where you can pass a function to be called before each request:
const client = axios.create({ baseURL: 'http://myapi.com/api/', json: true });
client.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if (isTokenGood(token)) {
return config;
} else {
logout();
}
});
If anyone is interested i ended up going with an interceptor as per #thanksd
My code index.js file in my api folder now looks like this
import axios from 'axios'
import router from '../router'
const client = axios.create({
baseURL : 'http://myapi.com/api/',
json: true
})
client.interceptors.response.use(function (response) {
return response
}, function (error) {
if (error.response.status === 401) {
router.push('/Login')
console.info('auth token expired')
localStorage.clear()
sessionStorage.clear()
} else if (error.response.status === 403) {
router.push('/Login')
} else {
return Promise.reject(error)
}
})
export default {
async execute(method, resource, data) {
const token = localStorage.getItem('token')
return client({
method,
url: resource,
data,
crossdomain: true ,
headers: { "Authorization": `Bearer ${token}` }
}).then(req => {
return req.data
})
},
getResponses() {
return this.execute('get', 'GetResponses')
},
getAll(){
return this.execute('get', 'GetAll')
},
I have an API api/auth that is used to log users in. It expects to receive an access_token (as URL query, from Headers, or from request body), a username, and a password. I've been using the Vue Chrome Developer Tool and even though I get a 201 response from the server, the auth.loggedIn state is still false. I think that might be the reason why my redirect paths on the nuxt.config.js isn't working as well. Can anyone point me to the right direction on why it doesn't work?
This is a screenshot of the Vue Chrome Developer Tool
This is the JSON response of the server after logging in. The token here is different from the access_token as noted above.
{
"token": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"user": {
"user_name": "xxxxxxxxxxxxxxxxxx",
"uid": "xxxxxxxxxxxxxxxxxx",
"user_data": "XXXXXXXXXXXXXXXXXXXXXXXXX"
}
}
Here is the relevant part of nuxt.config.js
export default {
modules: [
'#nuxtjs/axios',
'#nuxtjs/auth',
['bootstrap-vue/nuxt', { css: false }]
],
router: {
middleware: [ 'auth' ]
},
auth: {
strategies: {
local: {
endpoints: {
login: {
url: '/api/auth?access_token=XXXXXXXXXXXXXXXXXXXXXX',
method: 'post',
propertyName: 'token'
},
logout: {
url: '/api/auth/logout',
method: 'post'
},
user: {
url: '/api/users/me',
method: 'get',
propertyName: 'user'
}
}
}
},
redirect: {
login: '/',
logout: '/',
home: '/home'
},
token: {
name: 'token'
},
cookie: {
name: 'token'
},
rewriteRedirects: true
},
axios: {
baseURL: 'http://localhost:9000/'
}
}
And my store/index.js
export const state = () => ({
authUser: null
})
export const mutations = {
SET_USER: function (state, user) {
state.authUser = user
}
}
export const actions = {
nuxtServerInit ({ commit }, { req }) {
if (req.session && req.user) {
commit('SET_USER', req.user)
}
},
async login ({ commit }, { username, password }) {
const auth = {
username: username,
password: password
}
try {
const { user } = this.$auth.loginWith('local', { auth })
commit('SET_USER', user)
} catch (err) {
console.error(err)
}
}
}
The login action in the store is triggered by this method in the page:
export default {
auth: false,
methods: {
async login () {
try {
await this.$store.dispatch('login', {
username: this.form.email,
password: this.form.password
})
} catch (err) {
this.alert.status = true
this.alert.type = 'danger'
this.alert.response = err
}
}
}
}
P.S. I realize I'm explicitly including the access_token in the URL. Currently, I don't know where a master_key or the like can be set in the Nuxt Auth Module.
Try this in your store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = () => new Vuex.Store({
state: {
authUser: null
},
mutations: {
SET_USER: function (state, user) {
state.authUser = user
}
},
actions: {
CHECK_AUTH: function(token, router) {
if (token === null) {
router.push('/login')
}
}
}
})
export default store
And for the router, this should work globally:
$nuxt._router.push('/')