Wondering about Authentication In Vue Using Vuex? We can help you.
We have seen customers use local storage to manage tokens generated through client-side authentication.
Vuex serves as a centralized store for all the components in an application, with rules ensuring that the state can only be mutated in a predictable fashion.
As part of our Server Management Services, we assist our customers with several Vuex queries.
Today, let us see how we perform Authentication In Vue Using Vuex
Authentication In Vue Using Vuex
In order to begin, our Support Techs suggest having the following:
- Node on the local system
- Knowledge of JavaScript and Vue
- Vue CLI on the local system.
Set up the application modules
Today, we will create a Vue application that has Vuex and vue-router.
In order to set it up, we run:
$ vue create vue-auth
In the dialogue box, we add the necessary information and select the options we need and complete the installation.
Moving ahead, we install Axios:
$ npm install axios –save
Setup Axios
We need Axios across many of our components.
Open the ./src/main.js file and add the following:
[…] import store from ‘./store’ import Axios from ‘axios’ Vue.prototype.$http = Axios; const token = localStorage.getItem(‘token’) if (token) { Vue.prototype.$http.defaults.headers.common[‘Authorization’] = token } […]
Now, to use Axios inside our component, we can do this.$http
.
Setup Components
Moving ahead, we will see how our Support Techs set up the components.
-
The Login Component
Create a file Login.vue in the ./src/components directory. Then, add the template for the login page:
<template> <div> <form class=”login” @submit.prevent=”login”> <h1>Sign in</h1> <label>Email</label> <input required v-model=”email” type=”email” placeholder=”Name”/> <label>Password</label> <input required v-model=”password” type=”password” placeholder=”Password”/> <hr/> <button type=”submit”>Login</button> </form> </div> </template>
Once done, we add the data attributes that would bind to the HTML form:
[…] <script> export default { data(){ return { email : “”, password : “” } }, } </script>
Now, let us add the method for handling login:
[…] <script> export default { […] methods: { login: function () { let email = this.email let password = this.password this.$store.dispatch(‘login’, { email, password }) .then(() => this.$router.push(‘/’)) .catch(err => console.log(err)) } } } </script>
We are using a vuex action – login to handle this authentication.
-
The Register Component
This component is to register users. We begin by creating a file Register.vue in the components directory and add the following:
<template> <div> <h4>Register</h4> <form @submit.prevent=”register”> <label for=”name”>Name</label> <div> <input id=”name” type=”text” v-model=”name” required autofocus> </div> <label for=”email” >E-Mail Address</label> <div> <input id=”email” type=”email” v-model=”email” required> </div> <label for=”password”>Password</label> <div> <input id=”password” type=”password” v-model=”password” required> </div> <label for=”password-confirm”>Confirm Password</label> <div> <input id=”password-confirm” type=”password” v-model=”password_confirmation” required> </div> <div> <button type=”submit”>Register</button> </div> </form> </div> </template>
Let us define the data attributes we will bind to the form:
[…] <script> export default { data(){ return { name : “”, email : “”, password : “”, password_confirmation : “”, is_admin : null } }, } </script>
Then, we add the method for handling login:
[…] <script> export default { […] methods: { register: function () { let data = { name: this.name, email: this.email, password: this.password, is_admin: this.is_admin } this.$store.dispatch(‘register’, data) .then(() => this.$router.push(‘/’)) .catch(err => console.log(err)) } } } </script>
-
The Secure Component
This will only display if our user is authenticated. We create the component file, Secure.vue, and add the following:
<template> <div> <h1>This page is protected by auth</h1> </div> </template>
Update The App Component
Initially, we open ./src/App.vue file and add the following:
<template> <div id=”app”> <div id=”nav”> <router-link to=”/”>Home</router-link> | <router-link to=”/about”>About</router-link><span v-if=”isLoggedIn”> | <a @click=”logout”>Logout</a></span> </div> <router-view/> </div> </template>
Now, we will add the logic behind the log out:
<script> export default { computed : { isLoggedIn : function(){ return this.$store.getters.isLoggedIn} }, methods: { logout: function () { this.$store.dispatch(‘logout’) .then(() => { this.$router.push(‘/login’) }) } }, } </script>
Here, we did two things; compute the authentication state of the user and dispatch a logout action to our Vuex store when a user clicks the logout button. After the logout, we send the user to the login page using this.$router.push(‘/login’).
Vuex Auth Module
First, we will set up the store.js file for vuex:
import Vue from ‘vue’ import Vuex from ‘vuex’ import axios from ‘axios’ Vue.use(Vuex) export default new Vuex.Store({ state: { status: ”, token: localStorage.getItem(‘token’) || ”, user : {} }, mutations: { }, actions: { }, getters : { } })
We have now defined the attributes of the state. Now the Vuex state will hold our authentication status, jwt token, and user information.
Create The Vuex login Action
We use Vuex actions to commit mutations to the vuex store.
To create a login action, we open the ./src/store.js file and add the following to the actions object:
login({commit}, user){ return new Promise((resolve, reject) => { commit(‘auth_request’) axios({url: ‘http://localhost:3000/login’, data: user, method: ‘POST’ }) .then(resp => { const token = resp.data.token const user = resp.data.user localStorage.setItem(‘token’, token) axios.defaults.headers.common[‘Authorization’] = token commit(‘auth_success’, token, user) resolve(resp) }) .catch(err => { commit(‘auth_error’) localStorage.removeItem(‘token’) reject(err) }) }) },
The login action passes the Vuex commit helper that we use to trigger mutations.
We could store the token in vuex store, but if the user leaves our application, all of the data in the vuex store disappears.
To ensure we allow the user to return to the application within the validity time of the token and not have to log in again, we have to keep the token in localStorage.
We return a promise so we can return a response to a user after login is complete.
Create The Vuex register Action
The register action works almost similar to the login action. In the same file, we add the following:
register({commit}, user){ return new Promise((resolve, reject) => { commit(‘auth_request’) axios({url: ‘http://localhost:3000/register’, data: user, method: ‘POST’ }) .then(resp => { const token = resp.data.token const user = resp.data.user localStorage.setItem(‘token’, token) axios.defaults.headers.common[‘Authorization’] = token commit(‘auth_success’, token, user) resolve(resp) }) .catch(err => { commit(‘auth_error’, err) localStorage.removeItem(‘token’) reject(err) }) }) },
Create The Vuex logout Action
For the user to have the ability to log out of the system, we destroy all data created during the last authenticated session. In the object of the same action, we add the following:
logout({commit}){ return new Promise((resolve, reject) => { commit(‘logout’) localStorage.removeItem(‘token’) delete axios.defaults.headers.common[‘Authorization’] resolve() }) }
Now, when the user clicks to log out, we remove the jwt token. There is no way they can perform a transaction requiring a token now.
Create The Mutations
We use Mutators to change the state of a Vuex store. In the mutators object, we add:
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 = ” }, },
Create The Getters
We use getter to get the value of the attributes of the Vuex state. The role of our getter in the situation is to separate application data from application logic and ensure we do not give away sensitive information.
Add the following to the getters object:
getters : { isLoggedIn: state => !!state.token, authStatus: state => state.status, }
You would agree with me that this is a neater way to access data in the store.
Hide Pages Behind Auth
Our whole purpose is to implement authentication and keep pages away from unauthorized access.
For this, we need to have a track of the page the user wants to visit. Meanwhile, we need to check if the user has access or not.
In addition, we need a way to say if the page is reserved for only authenticated users or unauthenticated users, or both.
We can achieve these important considerations with Vue-router.
Define Routes For Authenticated And Unauthenticated Pages
Initially, open the ./src/router.js file and import things we need for the setup:
import Vue from ‘vue’ import Router from ‘vue-router’ import store from ‘./store.js’ import Home from ‘./views/Home.vue’ import About from ‘./views/About.vue’ import Login from ‘./components/Login.vue’ import Secure from ‘./components/Secure.vue’ import Register from ‘./components/Register.vue’ Vue.use(Router)
As you can see, right now we have vue, Vue-router, and our Vuex store setup.
Let us now define the routes:
[…] let router = new Router({ mode: ‘history’, routes: [ { path: ‘/’, name: ‘home’, component: Home }, { path: ‘/login’, name: ‘login’, component: Login }, { path: ‘/register’, name: ‘register’, component: Register }, { path: ‘/secure’, name: ‘secure’, component: Secure, meta: { requiresAuth: true } }, { path: ‘/about’, name: ‘about’, component: About } ] }) export default router
Handle Unauthorized Access Cases
Moving ahead, let us check for unauthorized access and take action.
In the router.js file, add the following before the export default router:
router.beforeEach((to, from, next) => { if(to.matched.some(record => record.meta.requiresAuth)) { if (store.getters.isLoggedIn) { next() return } next(‘/login’) } else { next() } })
While using Vue router for authentication, we had a really complex mechanism. However, Vuex helps us simplify that completely. Hence, we can go on to add any condition to our route.
Handle Expired Token Cases
Since we store our token in localStorage, it remains there perpetually. In such a case, what happens at most is that our requests will fail because of an invalid token.
In order to solve this, we open ./src/App.vue file and in the script, add:
export default { […] created: function () { this.$http.interceptors.response.use(undefined, function (err) { return new Promise(function (resolve, reject) { if (err.status === 401 && err.config && !err.config.__isRetryRequest) { this.$store.dispatch(logout) } throw err; }); }); } }
Here, we are intercepting Axios call to determine if we get 401 Unauthorized response. If yes, we dispatch the logout action and the user gets logged out of the application.
[Need help with the process? We can help you]
Conclusion
In short, we saw how to perform Authentication In Vue Using Vuex. Using Vuex allows us to store and manage authentication state and proceed to check state in our application using only a few lines of code.
0 Comments