Handling authentication in your GraphQL powered Vue app
Tags: graphql, vue, tutorial
Published: 2020-05-08 18:24:40

---
title: Handling authentication in your GraphQL powered Vue app
published: true
date: 2020-04-13 17:30:20 UTC
tags: graphql,vue,tutorial
canonical_url: https://blog.logrocket.com/handling-authentication-in-your-graphql-powered-vue-app/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/i9lbiydg91zjbvgja8m4.png
---
**Written by [Anjolaoluwa Adebayo-Oyetoro](https://blog.logrocket.com/author/anjolaoluwaadebayooyetoro/)**✏️

The primary goal of authentication is identifying the person requesting a resource. It is a very tricky subject when developing apps as there is no “one size fits all” rule for handling authentication in our apps.

Handling authentication on the client in a web-based application is even more tricky as there are security concerns such as cross-site scripting (XSS) where an attacker accesses information stored in the browser and uses it to masquerade as the user. Most SPAs implement a token-based authentication because tokens are stateless and they scale easily as it takes away the stress of your server keeping track of session state.

The flow for authenticating users in modern apps is usually in this format:

- The client sends a request to the authentication route with user information like email address and password
- The server checks the identity of the user, creates a JSON web token (JWT), and sends it back to the browser
- The client stores the token into one of the browser storage mediums(APIs)
- The client appends the token to the authorization header to make subsequent requests to the server

![Modern apps authentication flow](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/Modern-apps-authentication-flow.png?resize=2161%2C1536&ssl=1)

There are three storage options available for saving a token on the client, they include:

- Local storage
- Session storage
- Cookies

In this tutorial we’re going to take a look at how to handle authentication in a Vue app connected to a GraphQL API, we will do so by building a mini app. We will be making use of localStorage to store our token.

The API we will be connecting to can be found [here](https://bloggr-api.herokuapp.com/).

[![LogRocket Free Trial Banner](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2017/03/f760c-1gpjapknnuyhu8esa3z0jga.png?resize=1200%2C280&ssl=1)](https://logrocket.com/signup/)

## Prerequisites

This tutorial assumes the reader has the following:

- [Node.js 10x](https://nodejs.org/en/download/) or higher
- [Yarn](https://yarnpkg.com/lang/en/) / [npm 5.2 or higher installed](https://www.npmjs.com/get-npm) on their PC. This tutorial would be making use of Yarn
- Basic knowledge of JavaScript and how [Vue.js](https://vuejs.org/v2/guide) works
- Knowledge of how [GraphQL](https://www.graphql.com/) works
- [Vue CLI](https://cli.vuejs.org/) installed on your PC

You can install Vue CLI with the following command using Yarn:

```jsx
yarn global add @vue/cli
```

Tools we will be using to build our app include:

[Vue-Apollo](https://apollo.vuejs.org/) — This is an Apollo Client integration for Vue.js, it helps integrate GraphQL in our Vue.js apps!

[Vuex](https://vuex.vuejs.org/) — Vuex is a state management pattern library for Vue.js applications, it serves as a centralized store for all the components in an application. It is heavily influenced by the [Flux architectural pattern](https://facebook.github.io/flux/docs/in-depth-overview/) created by [Facebook](https://facebook.github.io/flux/).

[Vue Router](https://router.vuejs.org/) — This is the official routing library for [Vue.js](http://vuejs.org/), it makes routing in our Vue.js applications easier.

## Getting started

We will be using the Vue CLI tool to bootstrap a new Vue project, this tool helps us with not having to worry about configurations to get started with using our app as we can manually select the needed packages for our app.

First, we create a new project using the `create` command:

```jsx
vue create blogr
```

Move your down arrow key to “manually select features”, press enter and choose the following features:

![cli options](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/clioptions.png?resize=597%2C239&ssl=1)

Next, change directory into the project folder with this command:

```jsx
cd blogr
```

Start your project with the command:

```jsx
yarn serve
```

You should see your app running on [http://localhost:8080](http://localhost:8080) after running the yarn serve command.

![vue running app](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/vuerunningapp.png?resize=1320%2C710&ssl=1)

## Creating the user interface

Open your `App.vue` file located in your `src` folder and remove the following lines of code:

```jsx
<div id="nav">
  <router-link to="/">Home</router-link> |
  <router-link to="/about">About</router-link>
</div>
```

Replace the content removed with the following:

```jsx
<header class="header">
  <div class="app-name">Blogr</div>
    <div v-if="authStatus" id="nav">
      <div>{{user.name}}</div>
      <button class="auth-button" @click="logOut" > Log Out</button>
    </div>
</header>
```

We’re getting the name of the authenticated user and we’ve created a logout button that triggers a `logOut` method.

Next, navigate to `src/views` and create a `Register.vue` file and include the following lines of code in the file:

```jsx
<template>
  <div class="auth">
    <h3>Sign Up</h3>
    <form action="POST" @submit.prevent="registerUser">
      <label for="name"> Name</label>
      <input type="text" name="name"  placeholder="John Doe" v-model="authDetails.name" />
      <label for="email">Email Address</label>
      <input type="email" name="email"  placeholder="yourdopeemail@something.com" v-model="authDetails.email" />
      <label for="password">Password</label>
      <input type="password" name="password" placeholder="password" v-model="authDetails.password" />
      <button class="auth-submit">submit</button>
     <p class="auth-text"> Already have an account? <router-link to="/login"> Login </router-link> </p>
    </form>
  </div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
  name: 'Register',
  data () {
    return {
      authDetails: {
        name: '',
        email: '',
        password: ''
      }
    }
  },
  methods: {
    registerUser: function () {

    }
  }
}
</script>
```

In this code block, we’ve created the signup page without any functionality, clicking the submit button triggers the `registerUser` method which does nothing for now.

We’re using the v-model to create a two-way data binding on our input boxes to `authDetails`, if the value of our form changes, the value in `authDetails` changes alongside it.

Let’s add some style to our app, create a `styles` folder in `/src/assets`. Inside the `src` folder create an `index.css` file and include the following:

```jsx
.header {
    display: flex;
    justify-content: space-between;
    background-color: fuchsia;
    height: 25%;
    padding: 1rem;
}
.app-name {
    font-weight: 900;
    font-size: 3rem;
}
.auth {
    display: flex;
    flex-direction: column;
    align-items: center;
}
.auth h3 {
    margin-top: 2rem;
}
form {
    max-width: 50%;
    margin-top: 1rem;
    padding: 4rem;
    border: 1px solid #c4c4ce;
}
form input {
    display: block;
    margin-bottom: 1.2rem;
    padding: 0.4rem 1.2rem;
    background-color: white;
}
.auth-submit {
    margin-top: .5rem;
    padding: .5rem 1rem;
    border: none;
    background-color: fuchsia;
    color: white;
    font-weight: bold;
    text-transform: capitalize;
    border-radius: 0.3rem;
}
.auth-text a {
    color: black;
    text-decoration: none;
}
.auth-text a:visited {
    color: inherit;
}
.auth-text a:hover {
    text-decoration: underline;
}
.auth-text {
    margin-top: .5rem;
}
.auth-button{
    margin: .7rem 2rem 0 0;
    padding: .5rem 2rem;
    background-color: white;
    border: none;
    border-radius: .3rem;
}
main{
    margin-top: 5rem;
    display: flex;
    justify-content: center;
}
```

Next, let’s build the login page, create a `Login.vue` file in `src/views` and include the following in it:

```jsx
<template>
  <div class="auth">
    <h3>Log In</h3>
    <form action="POST" @submit.prevent="loginUser">
      <label for="email">Email Address</label>
      <input type="email" name="email"  placeholder="yourdopeemail@something.com" v-model="authDetails.email" />
      <label for="password">Password</label>
      <input type="password" name="password" placeholder="password" v-model="authDetails.password" />
      <button class="auth-submit">submit</button>
     <p class="auth-text"> Don't have an account? <router-link to="/"> Register </router-link> </p>
    </form>
  </div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
  name: 'Login',
  data () {
    return {
      authDetails: {
        email: '',
        password: ''
      }
    }
  },
  methods: {
    loginUser: function () {

    }
  }
}
</script>
```

This page is similar to our `Register.vue` page, clicking on the submit button triggers the `loginUser` method, which does nothing for now.

Next, replace the contents of `Home.vue` with the following:

```jsx
<template>
  <div class="home">
    <main>
     Yaay! User authenticated!
    </main>
  </div>
</template>
<script>
// @ is an alias to /src

export default {
  name: 'Home',
  components: {
  },
  computed: {

  }
}
</script>
```

This page will serve as our dashboard page that will be displayed to our user when they are authenticated:

![home vue](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/homevue.png?resize=1320%2C641&ssl=1)

## Configuring the routes

Next let’s include the routes for the login, register, and dashboard page in our router file located in `src/router/`.

Remove the contents in the `routes` array and add the following to the `index.js` file:

```jsx
{
   path: '/dashboard',
   name: 'Home',
   component: () => import('@/views/Home.vue'),
 },
 {
   path: '/login',
   name: 'Login',
   // route level code-splitting
   // this generates a separate chunk (login.[hash].js) for this route
   // which is lazy-loaded when the route is visited.
   component: () => import(/* webpackChunkName: "login" */ '@/views/Login.vue')
 },
 {
   path: '/',
   name: 'Register',
   // route level code-splitting
   // this generates a separate chunk (register.[hash].js) for this route
   // which is lazy-loaded when the route is visited.
   component: () => import(/* webpackChunkName: "register" */ '@/views/Register.vue')
 },
 {
   path: '*',
   redirect: 'login'
 }
```

These routes take advantage of Webpack’s code-splitting and are lazy-loaded, this inherently improves our app performance.

We also added a `*` – this is known as a wildcard router. The router will select this route if the requested URL doesn’t match any of the defined routes and the user will be redirected to the login page.

Our App should now look similar to this when you visit `localhost:8080`:

![registervue](https://i2.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/registervue.png?resize=1320%2C641&ssl=1)

## Installing Apollo Client with Vue-Apollo

Apollo Client is a complete GraphQL client for your UI framework, it helps you connect to, retrieve data, and modify data in a GraphQL server.

To integrate Apollo in our Vue app we will have to install the vue-apollo plugin for vue-cli:

```jsx
vue add apollo
```

![vue install plugin](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/vueinstallplugin.png?resize=540%2C136&ssl=1)

This plugin creates two files, `apollo.config.js` in the root directory of the project and `vue-apollo.js` in the `src` folder, it also injects Apollo provider in the Vue instance in `main.js`.

This provider makes it possible to use Apollo client instances in our Vue components. Next, let’s make some configurations to our `vue-apollo.js` file located in our `/src` folder.

Include the following at the top of the file contents:

```jsx
import { setContext } from 'apollo-link-context'
```

This helps us make use of `setContext` method when adding an `authorization` header to our HTTP requests.

Next, we change the `httpEndpoint` we would be connecting to. Replace the value of your `httpEndpoint` variable with this:

```jsx
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'https://bloggr-api.herokuapp.com/'
```

Add the following immediately after the `httpEndpoint` is defined:

```jsx
const authLink = setContext(async (_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = JSON.parse(localStorage.getItem('apollo-token'))
  // Return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token || ''
    }
  }
})
```

Next, we override the default Apollo link with our `authLink`, place the following in the `defaultOptions` object:

```jsx
link: authLink
```

The `defaultOptions` object sets application-wide default values for `apolloClient`.

Let’s proceed to create our `apolloClient` instance with our `defaultOptions` object as a value, we are exporting it with the `export` so we can access `apolloClient` in our `vuex` store:

```jsx
export const { apolloClient, wsClient } = createApolloClient({
  ...defaultOptions
  // ...options
})
```

Next, replace the `createProvider` function with the following:

```jsx
export function createProvider () {
  // Create vue apollo provider
  const apolloProvider = new VueApollo({
    defaultClient: apolloClient,
    defaultOptions: {
      $query: {
        fetchPolicy: 'cache-and-network'
      }
    },
    errorHandler (error) {
      // eslint-disable-next-line no-console
      console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message)
    }
  })
  return apolloProvider
}
```

The `createProvider` function gets called in the `main.js` file as soon as our app is initialized, it injects Apollo client instances into our Vue app and makes it possible to use Apollo in our components.

## Queries and mutations

Create a folder named `graphql` in your `/src` folder, inside it create two files with the following command:

```jsx
touch queries.js mutations.js
```

The `queries.js` file will contain queries to be made to our GraphQL server, a `Query` is a request made to the API to retrieve data. Queries are similar to `HTTP GET` requests in [REST APIs](https://dev.to/bnevilleoneill/the-essential-guide-for-designing-a-production-ready-developer-friendly-restful-api-1io).

The `mutations.js` file would contain mutations made to the GraphQL server, `Mutations` are queries that change the data state in your Apollo server. Mutations are similar to `HTTP PUT`, `POST`, or `DELETE` request in [REST APIs](https://dev.to/bnevilleoneill/the-essential-guide-for-designing-a-production-ready-developer-friendly-restful-api-1io).

Next, add the following lines of code in our `mutations.js` file:

```jsx
import gql from 'graphql-tag'
export const LOGIN_USER = gql`
mutation login ($email: String! $password: String! ){
  login(email: $email password: $password ){
    token
  }
}
`
export const REGISTER_USER = gql`
mutation createUser($name: String! $email: String! $password: String! ) {
    createUser( name: $name, email: $email, password: $password) {
      token
    }
}
`
```

`gql` helps us write our GraphQL queries, we’ve created the mutations for logging in and creating a new user, the contents of our form serves as the variables for our mutations.

In our `queries.js` file, Include the following query, the query gets the current authenticated user:

```jsx
import gql from 'graphql-tag'

export const LOGGED_IN_USER = gql`
  query {
    me {
      id
      name
      email
    }
  }
`
```

## Configuring Vuex

First, let’s import our `Mutations`, `Queries` , and the `apolloClient` instance:

```jsx
import { apolloClient } from '@/vue-apollo'
import { LOGGED_IN_USER } from '@/graphql/queries'
import { LOGIN_USER, REGISTER_USER } from '@/graphql/mutations'
```

Importing the `apolloClient` instance makes us able to perform Apollo operations in our store.

Next, set the data we will be needing in our `state`, put the following in the `state` object:

```jsx
token: null,
user: {},
authStatus: false
```

The [state object](https://vuex.vuejs.org/guide/state.html) is the central store for data that will be used application-wide. It represents a “single source of truth”.

The `authStatus` is a boolean that tells if a user is authenticated or not, the user object would contain the details of an authenticated user.

Next, we configure our `getters`, include the following in the `getters` object:

```jsx
isAuthenticated: state => !!state.token,
authStatus: state => state.authStatus,
user: state => state.user
```

[Getters](https://vuex.vuejs.org/guide/getters.html) help with retrieving items in our state object, a getter’s result is cached based on its dependencies, and will only re-evaluate when some of its dependencies have changed.

Proceed to create new [mutations](https://vuex.vuejs.org/guide/mutations.html), in the `mutations` object:

```jsx
SET_TOKEN (state, token) {
  state.token = token
},
LOGIN_USER (state, user) {
  state.authStatus = true
  state.user = { ...user }
},
LOGOUT_USER (state) {
  state.authStatus = ''
  state.token = '' && localStorage.removeItem('apollo-token')
}
```

We’ve created mutations to change state in a Vuex store, mutation functions are synchronous and they typically take two parameters — the state object and a payload which can be a variable or an object.

Finally, let’s configure our `actions`, [actions](https://vuex.vuejs.org/guide/actions.html) are asynchronous functions used to commit mutations. Actions are triggered with the `store.dispatch` method:

```jsx
async register ({ commit, dispatch }, authDetails) {
     try {
       const { data } = await apolloClient.mutate({ mutation: REGISTER_USER, variables: { ...authDetails } })
       const token = JSON.stringify(data.createUser.token)
       commit('SET_TOKEN', token)
       localStorage.setItem('apollo-token', token)
       dispatch('setUser')
     } catch (e) {
       console.log(e)
     }
   },
   async login ({ commit, dispatch }, authDetails) {
     try {
       const { data } = await apolloClient.mutate({ mutation: LOGIN_USER, variables: { ...authDetails } })
       const token = JSON.stringify(data.login.token)
       commit('SET_TOKEN', token)
       localStorage.setItem('apollo-token', token)
       dispatch('setUser')
     } catch (e) {
       console.log(e)
     }
   },
   async setUser ({ commit }) {
     const { data } = await apolloClient.query({ query: LOGGED_IN_USER })
     commit('LOGIN_USER', data.me)
   },
   async logOut ({ commit, dispatch }) {
     commit('LOGOUT_USER')
   }
```

Now that our store is configured, let’s add functionality to our login and register forms, include the following in the `script` section of your `Register.vue` file:

```jsx
<script>
import { mapActions } from 'vuex'
  ....
  methods: {
    ...mapActions(['register']),
    registerUser: function () {
      this.register(this.authDetails)
        .then(() => this.$router.push('/dashboard'))
    }
  }
...
```

To dispatch actions in our component, we’re using the `mapActions` helper which maps component methods to `this.$store.dispatch`.

The code above sends the form details as a payload to the `register` action in our Vuex store and then changes the route to `/dashboard`.

Include the following in your `Login.vue` file:

```jsx
<script>
import { mapActions } from 'vuex'
....
  methods: {
    ...mapActions(['login']),
    loginUser: function () {
      this.login(this.authDetails)
        .then(() => this.$router.push('/dashboard'))
    }
  }
...
```

Include the following in the `script` section of your `Home.vue` file to get user details:

```jsx
<script>

import { mapGetters } from 'vuex'
....
  computed: {
    ...mapGetters(['user'])
  }
....
</script>
```

The `mapGetters` helper simply maps store getters to local computed properties.

## Guarding routes

Import the `vuex` store at the top of your `router` file:

```jsx
import store from '../store'
```

Add a `meta` field to our `/dashboard` route, this `meta` helps us when defining our routes navigation guard middleware. Our dashboard route record will look similar to this:

```jsx
{
  path: '/dashboard',
  name: 'Home',
  component: () => import('@/views/Home.vue'),
  meta: { requiresAuth: true }
},
```

Include the following just before `export default router`:

```jsx
router.beforeEach((to, from, next) => {
    // Check if the user is logged i
  const isUserLoggedIn = store.getters.isAuthenticated
  if (to.matched.some(record => record.meta.requiresAuth)) {
    if (!isUserLoggedIn) {
      store.dispatch('logOut')
      next({
        path: '/login',
        query: { redirect: to.fullPath }
      })
    } else {
      next()
    }
  } else {
    next()
  }
})
```

This defines our navigation guard for our route records. When we navigate to any route with the `requiresAuth` meta field it checks if the user is authenticated and authorized to access that route and redirects the user to the login page if the user is not authorized.

Our finished application should look similar to this:

![vue app finished](https://i0.wp.com/blog.logrocket.com/wp-content/uploads/2020/04/finishedvue.gif?resize=730%2C353&ssl=1)

## Conclusion

In this post, we’ve seen how to handle authentication of our GraphQL APIs with vue-router, vue-apollo, and Vuex. You can learn more about Apollo GraphQL [here](https://www.apollographql.com/), you can also learn more about GraphQL on the [LogRocket](https://blog.logrocket.com/tag/graphql/) blog. Check out the [repository](https://github.com/Jolaolu/graphql-vue-auth) for this tutorial on GitHub, it can be used as a boilerplate to scaffold your app. You can also check out the GraphQL API [repository](https://github.com/Jolaolu/graphql-blog-api) and the deployed version of our [app](https://blogr.jola.now.sh/).

* * *
## Experience your Vue apps exactly how a user does 

Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, [try LogRocket.](https://www2.logrocket.com/vue-performance-monitoring)

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/t4ni6gomxqbkbxygmco0.png)

[LogRocket](https://www2.logrocket.com/vue-performance-monitoring) is like a DVR for web apps, recording literally everything that happens in your Vue apps including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.

The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.

Modernize how you debug your Vue apps - [Start monitoring for free.](https://www2.logrocket.com/vue-performance-monitoring)
* * *

The post [Handling authentication in your GraphQL powered Vue app](https://blog.logrocket.com/handling-authentication-in-your-graphql-powered-vue-app/) appeared first on [LogRocket Blog](https://blog.logrocket.com).