← Posts
Using Vuex to store authentication in Local Storage
December 28th, 2018 - 3 min read
I'm currently Rebuilding BiblioSpot as a standalone Vue app which fetches data from our private API. At the start of the project, I was wondering, how I should go about handling Authentication? I tried out a few different solutions but this one seems to work, so I'm going to go along with it.
The first thing I did was obviously create a new Vue app so I did vue create app-name. I chose Vue router, Vuex and some other stuff that was there that looked like a good option. I also installed Axios for the HTTP request stuff. Yes I know Vue has their own package for this and there is a similar function built into Javascript, but who cares.
Now, the first thing that we should do is to write code to allow the user to actually login. I'm using Laravel Passport for API auth and it gives us the /oauth/token route which we can send a payload to and it will give us our access token. A simple bit of code like this should do the jiffy.
1<template> 2 <div> 3 <h1>Login</h1> 4 <input v-model="email" type="email"> 5 <input v-model="password" type="password"> 6 </div> 7</template> 8 9<script>10import axios from 'axios'11export default {12 data: function() {13 return {14 email: '',15 password: '',16 response: ''17 }18 },19 methods: {20 post: function() {21 axios.post('[your site url]/oauth/token', {22 'grant_type': 'password',23 'client_id': [your client id],24 'client_secret': [your client secret],25 'username': this.email,26 'password': this.password,27 'scope': ''28 })29 .then(response => {30 this.response = response.data;31 this.$store.dispatch('bearer', this.response.access_token);32 this.$router.push('/')33 });34 }35 }36}37</script>
Once you've got your HTTP requests to work, you can create your Vuex store. This is a simplified version of my store.js file.
1import Vue from 'vue' 2import Vuex from 'vuex' 3 4Vue.use(Vuex) 5 6export default new Vuex.Store({ 7 state: { 8 user: { 9 bearer: ''10 }11 },12 13 mutations: {14 bearer (state, payload) {15 state.user.bearer = payload16 }17 },18 19 actions: {20 bearer (context, payload) {21 context.commit('bearer', payload)22 }23 },24 25 getters: {26 bearer: state => {27 return state.user.bearer28 }29 }30 31})
Basically what I've done in my Vuex store is set it up so that you can change and view the bearer/access token.
Now that we've got this in place, when you login your token should be set in your Vuex store and you should be directed to /. (you can change this route in the success part of the Axios request in the Login.vue component)
However, if you refresh the page, your bearer token is no longer in the Vuex store. This is where local storage comes in. It can store data that can be used even if you close the browser entirely.
The way I stored my state in local storage was by using the vuex-persistedstate npm package. You just need to install it and import it into your store, like so.
1import Vue from 'vue' 2import Vuex from 'vuex' 3import createPersistedState from 'vuex-persistedstate' 4 5Vue.use(Vuex) 6 7export default new Vuex.Store({ 8 plugins: [createPersistedState()] 9 10 state: {11 user: {12 bearer: ''13 }14 },15 16 mutations: {17 bearer (state, payload) {18 state.user.bearer = payload19 }20 },21 22 actions: {23 bearer (context, payload) {24 context.commit('bearer', payload)25 }26 },27 28 getters: {29 bearer: state => {30 return state.user.bearer31 }32 }33 34})
Now you should be able to login and refresh your page and your bearer token will still be in your store.
Now you've pretty much got everything working. However, if you need to check within views/components of your application if the user is logged in or out for that matter I've devised a little component that you can use that will detect such things and will redirect the user to the login page. (If you need to check that the user is logged out you can place the redirect at the other side of the if statement)
1<template> 2</template> 3 4<script> 5export default { 6 computed: { 7 loggedIn: function() { 8 return this.$store.getters.loggedIn 9 }10 },11 methods: {12 loginHandler: function() {13 if (this.loggedIn == true) {14 //15 } else {16 this.$router.push('/login')17 }18 }19 },20 mounted: function() {21 this.loginHandler()22 },23 watch: {24 loggedIn: function() {25 this.loginHandler26 }27 }28}29</script>
That's us done!