Add Authentication and Authorization to Vue.js Apps with Auth0 and GraphQL
Tags: graphql, auth0, vue, auth
Published: 2019-12-03 12:00:02

---
title: Add Authentication and Authorization to Vue.js Apps with Auth0 and GraphQL
published: true
date: 2019-04-01 10:56:15 UTC
tags: graphql, auth0, vuejs, auth
canonical_url: https://blog.hasura.io/add-authentication-and-authorization-to-vue-js-apps-with-auth0-graphql/
---

## TL;DR

- Add authentication to Vue.js app with Auth0
- Authorization using JWT and Hasura GraphQL permissions
- A sample Vue app protected by login to fetch articles written by logged in user
- [Source code](https://github.com/hasura/graphql-engine/tree/master/community/sample-apps/vuejs-auth0-graphql) for sample app

![](https://blog.hasura.io/content/images/2019/04/vuejs-auth-graphql-1.png)<figcaption>Vue.js + Auth0 + GraphQL + Hasura</figcaption>

## Tech Stack

The app uses the following stack that needs to be setup and configured to get it working:

- Vue.js with [vue-cli-plugin-apollo](https://vue-cli-plugin-apollo.netlify.com) and [vue-router](https://github.com/vuejs/vue-router)
- [Auth0](https://auth0.com) for authentication
- [Hasura GraphQL Engine](https://github.com/hasura/graphql-engine) for instant GraphQL APIs

Let's deploy Hasura along with postgres to get our GraphQL APIs ready.

## Deploy Hasura

[Hasura](https://hasura.io/) is an [open-source](https://github.com/hasura/graphql-engine) engine that gives you realtime GraphQL APIs on new or existing Postgres databases, with built-in support for stitching custom GraphQL APIs and triggering webhooks on database changes.

Follow the instructions in the [docs](https://docs.hasura.io/1.0/graphql/manual/getting-started/heroku-simple.html) to deploy Hasura. Note the Heroku URL for GraphQL Endpoint. You will be configuring this in the app later.

Apply the migrations by following the instructions in this [section](https://github.com/hasura/graphql-engine/tree/master/community/sample-apps/vuejs-auth0-graphql/app#create-the-initial-tables) to create the necessary database schema and permissions.

Now the backend is ready! You will be able to instantly query using Hasura GraphQL APIs. The endpoint will look like (https://myapp.herokuapp.com/v1alpha1/graphql). We will come back to this during the integration with the Vue app.

## Create an application in Auth0

1. Head to [Auth0 dashboard](http://manage.auth0.com/) and create an application in Single Page Web App type.

![](https://blog.hasura.io/content/images/2019/03/Auth0-Vuejs-App.png)

2.  In the settings of the application, add `http://localhost:3000/callback` as "Allowed Callback URLs" and `http://localhost:3000` as "Allowed Web Origins" to enable local development of the app

![](https://blog.hasura.io/content/images/2019/03/Auth0-URL-Setup.png)

## Add rules for custom JWT claims

In the Auth0 dashboard, navigate to "Rules". Add the following rules to add our custom JWT claims:

```
function (user, context, callback) {
  const namespace = "https://hasura.io/jwt/claims";
  context.idToken[namespace] = 
    { 
      'x-hasura-default-role': 'user',
      // do some custom logic to decide allowed roles
      'x-hasura-allowed-roles': user.email === 'admin@foobar.com' ? ['user', 'admin'] : ['user'],
      'x-hasura-user-id': user.user_id
    };
  callback(null, user, context);
}
```

## Get your JWT signing certificate

Head to [https://hasura.io/jwt-config](https://hasura.io/jwt-config) and generate the config for your Auth0 domain.

![](https://blog.hasura.io/content/images/2019/03/jwt-config.png)

Copy the JWT Config that is generated for the Autho app.

## Enable JWT Mode on Hasura

The config generated above needs to be used in the `HASURA_GRAPHQL_JWT_SECRET` environment variable. We also need to set the `HASURA_GRAPHQL_ADMIN_SECRET` key for the JWT mode to work.

![](https://blog.hasura.io/content/images/2019/03/heroku-jwt-mode-1.png)

Once you have added this, the GraphQL endpoints can only be queried using `Authorization` header or `X-Hasura-Admin-Secret` header.

## Create Auth0 Rule

Everytime user signups on Auth0, we need to sync that user into our postgres database. This is done using Auth0 rules. Create another **Rule** and insert the following code:

```
function (user, context, callback) {
  const userId = user.user_id;
  const nickname = user.nickname;
  
  request.post({
  headers: {'content-type' : 'application/json', 'x-hasura-admin-secret': '<your-admin-secret>'},
  url: 'http://myapp.herokuapp.com/v1alpha1/graphql',
  body: `{\"query\":\"mutation($userId: String!, $nickname: String) {\\n insert_users(\\n objects: [{ auth0_id: $userId, name: $nickname }]\\n on_conflict: {\\n constraint: users_pkey\\n update_columns: [last_seen, name]\\n }\\n ) {\\n affected_rows\\n }\\n }\",\"variables\":{\"userId\":\"${userId}\",\"nickname\":\"${nickname}\"}}`
}, function(error, response, body){
    console.log(body);
    callback(null, user, context);
});
}
```

Replace the `admin secret` and `url` appropriately.

Finally we have the full backend and auth setup ready. Let's configure the Vue.js frontend to make the GraphQL query with the right headers.

## Configure Vue-CLI-Apollo-Plugin

We will be using the [Auth0's sample app](https://github.com/auth0-samples/auth0-vue-samples/tree/master/01-Login) to get started with boilerplate code.

The following command generates apollo client setup for a Vue app.

```
vue add apollo
```

This will generate a file called `vue-apollo.js` in `src`. In this file, we will be configuring the `options` object, `getAuth` by defining the following:

```
getAuth: tokenName => {
    // get the authentication token from local storage if it exists
    // return the headers to the context so httpLink can read them
    const token = localStorage.getItem('apollo-token')
    if (token) {
      return 'Bearer ' + token
    } else {
      return ''
    }
},
```

This configuration ensures that ApolloClient makes use of the token returned by Auth0 for `Authorization` header when making its query or subscription.

## Authenticated Query

Apollo Client has been configured with the right headers in the above setup. So let's add a simple query to fetch list of articles written by the user who is logged in.

```
export default {
  apollo: {
    // Simple query that will update the 'article' vue property
    article: gql`query {
      article {
        id
        title
      }
    }`,
  },
}
```

Now we would like to show this only if the user is logged in to the app.

So in our `<template>` tag of `Home.vue`, we will be using the following code snippet to list the articles

```
<template>
    ...
    ...
    <div v-if="isAuthenticated">
      <h1 class="mb-4">
        Articles written by me
      </h1>
      <div v-for="a in article" :key="a.id">
        {{a.id}}. {{ a.title }}
      </div> 
    </div>
    ...
    ...
</template>
```

Note that we are ensuring that this markup has to be rendered only if `isAuthenticated` returns true. To implement this, we emit an event after each successful login.

Head to `src/auth/authService.js` to see the implementation details of Auth0 login and event emitting.

In this file, an event is emitted once the login is done successfully.

```
this.emit(loginEvent, {
  loggedIn: true,
  profile: authResult.idTokenPayload,
  state: authResult.appState || {}
});
```

A `plugin` has been registered to handle this event in `src/plugins`

```
import authService from "../auth/authService";

export default {
  install(Vue) {
    Vue.prototype.$auth = authService;

    Vue.mixin({
      created() {
        if (this.handleLoginEvent) {
          authService.addListener("loginEvent", this.handleLoginEvent);
        }
      },

      destroyed() {
        if (this.handleLoginEvent) {
          authService.removeListener("loginEvent", this.handleLoginEvent);
        }
      }
    });
  }
};
```

So once a `loginEvent` occurs, `handleLoginEvent` method is called.

And in our `Home.vue` component, we handle that method to update `isAuthenticated` value. It is `false` by default and once login is successful, gets updated to `true`.

```
methods: {
    handleLoginEvent(data) {
      this.isAuthenticated = data.loggedIn;
      this.isLoading = false;
    }
},
```

The GraphQL query above is sent using the token header returned by Auth0 and this takes care of the Authentication.

## Authorization using JWT

Though the user is logged in, we want to show only the articles written by the same user. The permissions have been configured in such a way that only the user who wrote the article will be able to fetch the data.

Head to the Heroku app URL to open Hasura console and navigate to                   **Data-\>article-\>Permissions** to see the permissions defined for the `user` role.

![](https://blog.hasura.io/content/images/2019/03/hasura-console-permissions-page.png)

The permission check looks like:

```
{ "user_id": {"_eq": "X-Hasura-User-Id"}}
```

This means that when a request is being sent with `Authorization: Bearer <token>` from the client, it will look for the `X-Hasura-User-Id` value from the token payload and filter it for the `user_id` column, ensuring that only logged in users get the data and also **get only their data**. The user has permissions to access all columns.

## Protected Routes using Vue Router

Since we are using **[Vue Router](https://github.com/vuejs/vue-router)**, we can add `Navigation Guards` using a `Global Before Guard`. This is called whenever a navigation is triggered and the navigation is considered pending until resolved.

In `src/router.js`, we define the `beforeEach` guard which checks for the boolean `auth.isAuthenticated()` before resolving.

```
router.beforeEach((to, from, next) => {
  if (to.path === "/" || to.path === "/callback" || auth.isAuthenticated()){
    return next();
  }

  auth.login({ target: to.path });
});
```

In case, the page is not `/`, `/callback` or the user is not authenticated, then the user is redirected to Login page using `auth.login` method.

## Running the App

We need to configure the Hasura GraphQL Endpoint in the Vue.js app. Go to `src/vue-apollo.js` and modify the `httpEndpoint` and `wsEndpoint` values appropriately.

Run the sample app by running the following commands:

```
npm install
npm run serve
```

You should be seeing a screen like this:

![](https://blog.hasura.io/content/images/2019/04/vuejs-auth-landing-page.png)

I have put together a boilerplate so that you can get started quickly!

Check it out on [github](https://github.com/hasura/graphql-engine/tree/master/community/sample-apps/vuejs-auth0-graphql).

Take it for a spin and let us know what you think. If you have any questions or run into any trouble, feel free to reach out to us on [twitter](https://twitter.com/hasurahq), [github](https://github.com/hasura/graphql-engine) or on our [discord server](https://discord.gg/vBPpJkS).

----

This article was originally published on the [Hasura blog](https://blog.hasura.io/) and was authored by Praveen Durairaj.