Every web application that handles user-specific data needs to implement authentication. Knowing how to do this is important for Vue developers, and that’s what this article aims to shed the spotlight on. This tutorial will prove to be useful for beginner developers who want to learn about authentication in Vue. In order to be able to follow along, you’ll need to have a good knowledge of Vue and Vuex.
Authentication is a very necessary feature for applications that store user data. It’s a process of verifying the identity of users, ensuring that unauthorized users cannot access private data — data belonging to other users. This leads to having restricted routes that can only be accessed by authenticated users. These authenticated users are verified by using their login details (i.e. username/email and password) and assigning them with a token to be used in order to access an application’s protected resources.
In this article, you’re going to be learning about:
We will be working with the following dependencies that help in authentication:
We will be working with these tools and see how they can work together to provide robust authentication functionality for our app.
We will be building a simple blog site, which will make use of this API. You can check out the docs to see the endpoints and how requests should be sent.
From the docs, you’ll notice few endpoints are attached with a lock. This is a way to show that only authorized users can send requests to those endpoints. The unrestricted endpoints are the /register
and /login
endpoints. An error with the status code 401
should be returned when an unauthenticated user attempts to access a restricted endpoint.
After successfully logging in a user, the access token alongside some data will be received in the Vue app, which will be used in setting the cookie and attached in the request header to be used for future requests. The backend will check the request header each time a request is made to a restricted endpoint. Don’t be tempted to store the access token in the local storage.
Using the Vue CLI, run the command below to generate the application:
vue create auth-project
Navigate into your new folder:
cd auth-project
Add the vue-router and install more dependencies — vuex and axios:
vue add router
npm install vuex axios
Now run your project and you should see what I have below on your browser:
npm run serve
Axios is a JavaScript library that is used to send requests from the browser to APIs. According to the Vuex documentation;
“Vuex is a state management pattern + library for Vue.js applications. It 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.”
What does that mean? Vuex is a store used in a Vue application that allows us to save data that will be available to every component and provide ways to change such data. We’ll use Axios in Vuex to send our requests and make changes to our state (data). Axios will be used in Vuex actions
to send GET
and POST
, response gotten will be used in sending information to the mutations
and which updates our store data.
To deal with Vuex resetting after refreshing we will be working with vuex-persistedstate, a library that saves our Vuex data between page reloads.
npm install --save vuex-persistedstate
Now let’s create a new folder store
in src
, for configuring the Vuex store. In the store
folder, create a new folder; modules
and a file index.js
. It’s important to note that you only need to do this if the folder does not get created for you automatically.
import Vuex from 'vuex';
import Vue from 'vue';
import createPersistedState from "vuex-persistedstate";
import auth from './modules/auth';
// Load Vuex
Vue.use(Vuex);
// Create store
export default new Vuex.Store({
modules: {
auth
},
plugins: [createPersistedState()]
});
Here we are making use of Vuex
and importing an auth module
from the modules
folder into our store.
Modules are different segments of our store that handles similar tasks together, including:
Before we proceed, let’s edit our main.js
file.
import Vue from 'vue'
import App from './App.vue'
import router from './router';
import store from './store';
import axios from 'axios';
axios.defaults.withCredentials = true
axios.defaults.baseURL = 'https://gabbyblog.herokuapp.com/';
Vue.config.productionTip = false
new Vue({
store,
router,
render: h => h(App)
}).$mount('#app')
We imported the store
object from the ./store
folder as well as the Axios package.
As mentioned earlier, the access token cookie and other necessary data got from the API need to be set in the request headers for future requests. Since we’ll be making use of Axios when making requests we need to configure Axios to make use of this. In the snippet above, we do that using axios.defaults.withCredentials = true
, this is needed because by default cookies are not passed by Axios.
aaxios.defaults.withCredentials = true
is an instruction to Axios to send all requests with credentials such as; authorization headers, TLS client certificates, or cookies (as in our case).
We set our axios.defaults.baseURL
for our Axios request to our API
This way, whenever we’re sending via Axios, it makes use of this base URL. With that, we can add just our endpoints like /register
and /login
to our actions without stating the full URL each time.
Now inside the modules
folder in store
create a file called auth.js
//store/modules/auth.js
import axios from 'axios';
const state = {
};
const getters = {
};
const actions = {
};
const mutations = {
};
export default {
state,
getters,
actions,
mutations
};
state
In our state dict, we are going to define our data, and their default values:
const state = {
user: null,
posts: null,
};
We are setting the default value of state
, which is an object that contains user
and posts
with their initial values as null
.
Actions are functions that are used to commit
a mutation to change the state or can be used to dispatch
i.e calls another action. It can be called in different components or views and then commits mutations of our state;
Register Action
Our Register
action takes in form data, sends the data to our /register
endpoint, and assigns the response to a variable response
. Next, we will be dispatching our form username
and password
to our login
action. This way, we log in the user after they sign up, so they are redirected to the /posts
page.
async Register({dispatch}, form) {
await axios.post('register', form)
let UserForm = new FormData()
UserForm.append('username', form.username)
UserForm.append('password', form.password)
await dispatch('LogIn', UserForm)
},
Login Action
Here is where the main authentication happens. When a user fills in their username and password, it is passed to a User
which is a FormData object, the LogIn
function takes the User
object and makes a POST
request to the /login
endpoint to log in the user.
The Login
function finally commits the username
to the setUser
mutation.
async LogIn({commit}, User) {
await axios.post('login', User)
await commit('setUser', User.get('username'))
},
Create Post Action
Our CreatePost
action is a function, that takes in the post
and sends it to our /post
endpoint, and then dispatches the GetPosts
action. This enables the user to see their posts after creation.
async CreatePost({dispatch}, post) {
await axios.post('post', post)
await dispatch('GetPosts')
},
Get Posts Action
Our GetPosts
action sends a GET
request to our /posts
endpoint to fetch the posts in our API and commits setPosts
mutation.
async GetPosts({ commit }){
let response = await axios.get('posts')
commit('setPosts', response.data)
},
Log Out Action
async LogOut({commit}){
let user = null
commit('logout', user)
}
Our LogOut
action removes our user
from the browser cache. It does this by committing a logout
:
const mutations = {
setUser(state, username){
state.user = username
},
setPosts(state, posts){
state.posts = posts
},
LogOut(state){
state.user = null
state.posts = null
},
};
Each mutation takes in the state
and a value from the action committing it, aside Logout
. The value gotten is used to change certain parts or all or like in LogOut
set all variables back to null.
Getters are functionalities to get the state. It can be used in multiple components to get the current state. The isAuthenticatated
function checks if the state.user
is defined or null and returns true
or false
respectively. StatePosts
and StateUser
return state.posts
and state.user
respectively value.
const getters = {
isAuthenticated: state => !!state.user,
StatePosts: state => state.posts,
StateUser: state => state.user,
};
Now your whole auth.js
file should resemble my code on GitHub.
#vue #javascript #web-development #programming #developer