
## Vue Authentication

At this point we are ready to start working on our frontend VueJS application in more detail. To start, we will want to do the following:

- Install additional packages to be used with our VueJS application:
  - [`axios`](https://github.com/axios/axios): a Promise based HTTP client for the browser and node.js
  - [`element-ui`](https://element.eleme.io/#/en-US): a Vue 2.0 based component library for developers, designers and product managers

- Remove the boilerplate code that was autogenerated

- Build out a basic layout with a side menu and nav bar.

- Build in authentication so only authenticated users can see our app using `axios` and `element-ui`
  - All other users will be redirected to the `login` page

To begin, let's install `axios` and `element-ui`. To install these packages, we can add the package name and version to `dependencies` in `package.json`.

**package.json**

```json
  "dependencies": {
    "element-ui":"^2.4.8",
    "axios":"^0.17.1",
    ...
  }
```

Now, when we run `npm run install` in either the development or production environment, we will install these packages with `npm` and have access to them from our Vue application.

Let's launch the development environment and see this in action:

```
docker-compose -f docker-compose.dev.yml up --build
```

Let's globally import `Element UI` as recommmended in the [official documentation](https://element.eleme.io/#/en-US/component/quickstart#import-element). In `main.js`, add the following code:

**frontend/src/main.js**

```js
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './App.vue';
import router from './router';
import store from './store';
import './registerServiceWorker';

Vue.use(ElementUI);

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app');
```

Now we can use Element UI components anywhere in our project without having to import them in each file where they are used.

Let's commit our changes and then start on implementing our authentication system.

```
git add .
git commit -m "added element ui and axios libraries"
```

Let's start with an example of authentication in VueJS using JWTs from [sqreen.io](https://blog.sqreen.io/authentication-best-practices-vue/), a company that specializes in automated security for web apps. The code for the authentication example is available [here](https://github.com/sqreen/vue-authentication-example/tree/master/src).

Let's compare the structure of the `src` directories in our project and the sqreen.io example:

Our project's `src`:

```
.
├── App.vue
├── components
├── main.js
├── registerServiceWorker.js
├── router.js
├── store.js
└── views
    ├── About.vue
    └── Home.vue
```

sqreen.io's `src`:

```
.
├── App.vue
├── components
│   ├── account
│   │   └── index.vue
│   ├── footer
│   │   └── index.vue
│   ├── home
│   │   ├── fakeFeed.js
│   │   ├── feedItem.vue
│   │   └── index.vue
│   ├── lib
│   │   ├── center-container.vue
│   │   └── loading.vue
│   ├── login
│   │   └── index.vue
│   └── navigation
│       └── index.vue
├── main.js
├── router
│   └── index.js
├── store
│   ├── actions
│   │   ├── auth.js
│   │   └── user.js
│   ├── index.js
│   └── modules
│       ├── auth.js
│       └── user.js
└── utils
    └── api.js
```

Let's rearrange our Vue app so that it has the same files structure as the sqreen app. Leave blank files in the folders you create as placeholders and we will fill them in in a way that works with our Django backend and the Element UI component library.

Remove the `router.js` and `store.js` files in the root of our project.

Let's start with the `main.js` file. We first import `Vue`, `App`, `router` and `store`. We can leave these import statements as they are in our `main.js`. We moved these files, but we also renamed them to `index.js`, so importing the name of the parent folder will import the `index.js` file by default.

Next let's import `Loading` and `CenterContainer` and then register these components globally:

```js
import Loading from 'components/lib/loading'
import CenterContainer from 'components/lib/center-container'

Vue.component('loading', Loading)
Vue.component('center-container', CenterContainer)
```

Now let's look at `App.vue`, the component we pass into the `template` of our Vue instance. Here's the template:

```html
<template>
  <div id="app">
    <navigation/>
    <div class="main-container">
      <center-container>
        <router-view/>
      </center-container>
    </div>
    <sqreen-footer/>
  </div>
</template>
```

This template makes use of the `center-container` and `router-view` components that we imported in `main.js`. It also uses the `navigation` and `sqreen-footer` that we specify in the `components` property. `<router-view>` will display the component that corresponds to the current route. We will look at the routes file shortly.

This template will make it difficult to not show the `navigation` and `footer` components. Later we may want to change the template here to include only `router-view`. Then, we can include any layout depending on the current route. Changing this will be easy, but let's move on for now.

```html
<script>
import Navigation from 'components/navigation'
import { USER_REQUEST } from 'actions/user'
import SqreenFooter from './components/footer/index.vue'

export default {
  components: {
    SqreenFooter,
    Navigation },
  name: 'app',
  created: function () {
    if (this.$store.getters.isAuthenticated) {
      this.$store.dispatch(USER_REQUEST)
    }
  }
}
</script>
```

The script section imports two components and an `action` from the `store`. Let's talk about the store after we have a look at the `router` file.

### Frontend routes used for authentication

**src/router/index.js**

```js
import Vue from 'vue'
import Router from 'vue-router'
import Home from 'components/home'
import Account from 'components/account'
import Login from 'components/login'
import store from '../store'

Vue.use(Router)

const ifNotAuthenticated = (to, from, next) => {
  if (!store.getters.isAuthenticated) {
    next()
    return
  }
  next('/')
}

const ifAuthenticated = (to, from, next) => {
  if (store.getters.isAuthenticated) {
    next()
    return
  }
  next('/login')
}

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'Home',
      component: Home,
    },
    {
      path: '/account',
      name: 'Account',
      component: Account,
      beforeEnter: ifAuthenticated,
    },
    {
      path: '/login',
      name: 'Login',
      component: Login,
      beforeEnter: ifNotAuthenticated,
    },
  ],
})
```

Here we are importing the Router, registering it to Vue, defining functions that will be called before the `/account` and `/login` routes are visited. We see this in the `beforeEnter` property in the `routes` attribute in the `Router` we are instantiating to be used in our application.

### Login route

Let's start with the `/login` route.

If we visit `/login`, we will first run the `ifNotAuthenticated` function. This function checks the `store` for the value of `store.getters.isAuthenticated`. Let's look at what this getter does:

**src/store/modules/auth.js**

```js
const getters = {
  isAuthenticated: state => !!state.token,
  authStatus: state => state.status,
}
```

If there is a token in the `state`, `isAuthenticated` returns `true`. In this case, `ifNotAuthenticated` will redirect to `/`. If there is not token, we call `next()`. Next will then render our `Login` component.

`ifNotAuthenticated` is a global guard. You can read more about global guards in the [Vue Router documentation](https://router.vuejs.org/guide/advanced/navigation-guards.html#global-guards).

We do something similar with the `/account` route. Before we access this route, we run `ifAuthenticated`. This function redirects to `/login` if there is no token in storage.

Let's now look at the `Login` component:

```html
<template>
  <div>
    <form class="login" @submit.prevent="login">
      <h1>Sign in</h1>
      <label>User name</label>
      <input required v-model="username" type="text" placeholder="Snoopy"/>
      <label>Password</label>
      <input required v-model="password" type="password" placeholder="Password"/>
      <hr/>
      <button type="submit">Login</button>
    </form>
  </div>
</template>
```

This is a fairly standard login form for Vue. Notice how we place the `@submit` action on the form, not the `button` in the form.

```js
<script>
  import {AUTH_REQUEST} from 'actions/auth'

  export default {
    name: 'login',
    data () {
      return {
        username: '',
        password: '',
      }
    },
    methods: {
      login: function () {
        const { username, password } = this
        this.$store.dispatch(AUTH_REQUEST, { username, password }).then(() => {
          this.$router.push('/')
        })
      }
    },
  }
</script>
```

In the `script` section we import `AUTH_REQUEST` from `actions/auth`. In `methods`, we define the `login` method that is called when the form is submitted. We dispatch the `AUTH_REQUEST` with the `username` and `password` as arguments to this action.

Let's look at `AUTH_REQUEST`:

```js
  [AUTH_REQUEST]: ({commit, dispatch}, user) => {
    return new Promise((resolve, reject) => {
      commit(AUTH_REQUEST)
      apiCall({url: 'auth', data: user, method: 'POST'})
      .then(resp => {
        localStorage.setItem('user-token', resp.token)
        // Here set the header of your ajax library to the token value.
        // example with axios
        // axios.defaults.headers.common['Authorization'] = resp.token
        commit(AUTH_SUCCESS, resp)
        dispatch(USER_REQUEST)
        resolve(resp)
      })
      .catch(err => {
        commit(AUTH_ERROR, err)
        localStorage.removeItem('user-token')
        reject(err)
      })
    })
  }
```

This method might look a little bit strange if you are not familiar with ES6. `[AUTH_REQUEST]:` is simply the name of the attribute. The arguments section `({commit, dispatch}, user)` uses destructuring assignment. You can read more about that [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Syntax).

`commit` and `dispatch` are part of `context`. In short, `commit` and `dispatch` together will allow us to change the global state. Let's see how this works. The function returns a Promise, and right away we see `commit(AUTH_REQUEST)`. This may seem confusing because we are already in the body of a function called `AUTH_REQUEST`.

In Vue, you *`commit`* **`mutations`** and you *`dispatch`* **`actions`**. Committing a mutation is a synchronous action. It happens right away, and doesn't need to wait for a response from a remote server. Dispatching actions is an asynchronous event.

Back in the `login` method, we dispathed an action:

```js
this.$store.dispatch(AUTH_REQUEST, { username, password })
```

Inside this action, we can commit a mutation. In `src/store/modules/auth.js`, we have an object called `mutations`, and one of the properties of this object is `AUTH_REQUEST`. This is the function that is called when we *commit* the `AUTH_REQUEST` **mutation** inside of the `AUTH_REQUEST` action. Here's what the mutation looks like:

```js
  [AUTH_REQUEST]: (state) => {
    state.status = 'loading'
  },
```

It simply set the state's status to `loading`. This makes sense for a synchronous **mutation**. This will update the template where we have a `<v-if>` in the `Home` component:

```html
<loading v-if="loading"/>
```

This will display the spinner. We want to display the loading spinner while we wait for our Promise to resolve. Right after we turn on the loading spinner, we call `apiCall({url: 'auth', data: user, method: 'POST'})`.

The `apiCall` function is imported from `utils/api`. This function simulates a `POST` request to a server, and when it is resolved it returns the following:

```js
{ token: 'This-is-a-mocked-token' }
```

So the mock `apiCall` doesn't actually check the username or password. It assumes that whatever we entered is the correct username/password for the mock user.

Then, save this token returned be `apiCall` in `localStorage`. You can view local storage by opening the Chrome developer console's Application tab. Each unqiue domain will have it's own local storage where the key value data pairs can be saved for a given website.

After we set the token in `localStorage`, we see the following:

```js
        // Here set the header of your ajax library to the token value.
        // example with axios
        // axios.defaults.headers.common['Authorization'] = resp.token
```

Let's uncomment this code and set the axios header with the returned token:

```js
        axios.defaults.headers.common['Authorization'] = resp.token
```

Next, we commit the `AUTH_SUCCESS` mutation which does the following:

```js
  [AUTH_SUCCESS]: (state, resp) => {
    state.status = 'success'
    state.token = resp.token
    state.hasLoadedOnce = true
```

Setting the state's status to `success` will remove the loading spinner. Also, we will see the list of Posts displayed:

```html
    <div v-if="isAuthenticated">
      <feed-item v-for="(feed, index) in fakeFeed" :key="index" :feed="feed"/>
    </div>
```

`isAuthenticated` is a computed property in our `Home` component and it is made available by calling:

```js
...mapGetters(['isAuthenticated', 'authStatus']),
```

`mapGetters` is a utility that will allow us to use Vues getters as if they are getters of the `Home` component.

Once again, `isAuthenticated` does the following: `isAuthenticated: state => !!state.token`.

This will return true, because we now have a token in our state, so we will see the posts displayed in the `Home` component.

Now that we have seen a little bit of the authentication process, let's go back to `App.vue` and look at the `created` function:

```js
  created: function () {
    if (this.$store.getters.isAuthenticated) {
      this.$store.dispatch(USER_REQUEST)
    }
  }
```

If the user `isAuthenticated`, we will *`dispatch`* the `USER_REQUEST` **`action`**.

Let's look at the `USER_REQUEST` action:

```js
  [USER_REQUEST]: ({commit, dispatch}) => {
    commit(USER_REQUEST)
    apiCall({url: 'user/me'})
      .then(resp => {
        commit(USER_SUCCESS, resp)
      })
      .catch(resp => {
        commit(USER_ERROR)
        // if resp is unauthorized, logout, to
        dispatch(AUTH_LOGOUT)
      })
  },
```

This makes another mock request, but this time we are making a `GET` request to `user/me`. This will return the following:

```js
  'user/me': { 'GET': { name: 'doggo', title: 'sir' } }
```

Then, we *`commit`* the `UESR_SUCCESS` **`mutation`** (synchronous action). Let's look at the `USER_SUCCESS` mutation:

```js
  [USER_SUCCESS]: (state, resp) => {
    state.status = 'success'
    Vue.set(state, 'profile', resp)
  },
```

This function will set the status to success and then set the state's `profile` value to be the user's profile that is returned by the mock API.

Changing the profile state will change the Navigation bar to display the user's profile information. This is because of the `v-if` on the `<li>` tag in the nav bar:

```html
      <li v-if="isProfileLoaded">
        <router-link to="/account">{{name}}</router-link>
      </li>
```

`isProfileLoaded` is a getter that will react to changes in the global state because we include it in the list we pass to `mapGetters` which is then spread into the component's `computed` property.


```js
      ...mapGetters(['getProfile', 'isAuthenticated', 'isProfileLoaded']),
```

There's a lot to unpack with this authentication system, so I won't cover every file and function that plays a role, but it may be helpful if you can think about the process of login in to the site on the browser and think about what should be happening in the code. This will give you a more inuitive understanding of the code. For example. Think about what happens when the user is logged in in one tab and then opens a new tab to the `/accounts` route. Will the user be signed in automatically? How?

Once you have replicated this project in you local machine, make sure that you can log in and log out. Also, open up the `Application` tab in the Chrome developer console and verify that we are saving the mock token to local storage.

Let's pause here and commit our changes.

```
git add .
git commit -m "added mock authentication example from sqreen.io"
```

## Replace mock login API with Django API

Now that we have a functioning mock login system, let's think about what we need to do in order to use the JWT auth system we made previously in Django.

We will want to:

- Replace `apiCall` in `src/utils/api.js` with a `POST` request using `axios`
- Add a protected `/posts` route that we will only be able to see if we are logged in.

### axios

First, let's import axios in `api.js` and create an axios instance:

```js
import axios from 'axios';

// create an axios instance
const service = axios.create({
  baseURL: 'localhost',
})
```

Next we want to add a request interceptor to `service` that will add our token to the request header (if a token exists) before each request is sent out. Here's an example from axios's [github page](https://github.com/axios/axios):

```js
// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });
```

In our code, we can add the following:

```js
import axios from 'axios';
import store from '../store';

const apiCall = axios.create({
  baseURL: 'localhost',
});

// request interceptor
apiCall.interceptors.request.use(
  config => {
    // Do something before each request is sent
    if (store.getters.token) {
      // Attach a token to the header
      config.headers['JWT'] = store.token
    }
    return config
  },
  error => {
    // Do something with the request error
    Promise.reject(error)
  }
)

export default apiCall
```

Now let's use this new `apiCall`. When a user logs in, the login form calls the `login` method. This dispatches `AUTH_REQUEST`. Here's our new `AUTH_REQUEST` in `src/store/modules/auth.js` (with comments):

```js
  [AUTH_REQUEST]: ({commit, dispatch}, user) => { //define `AUTH_REQUEST` action
    return new Promise((resolve, reject) => { // return a Promise
      commit(AUTH_REQUEST) // commit `AUTH_REQUEST` mutation; displays the Loading spinner or message
      apiCall.post( // use our new apiCall
        '/api/auth/obtain_token/', // the login endpoint for our Django backend
        user // this contains { username: "admin", password: "password" }, our form data
      )
      .then(resp => { // response comes back from the backend
        // console.log(resp); // log the output of the response for debuging
        localStorage.setItem('user-token', resp.data.token) // save the token returned in the response to localStorage
        commit(AUTH_SUCCESS, resp) // remove the loading spinner, save the token to our store
        dispatch(USER_REQUEST) // get the logged in user's profile information
        resolve(resp) // resolve the promise
      })
      .catch(err => { // handle a bad request
        // console.log("Incorrect username/password"); // handle a bad password
        console.log(err.status); // log the repsonse
        commit(AUTH_ERROR, err) // set auth status to error
        localStorage.removeItem('user-token') // remove `user-token` from localStorage
        reject(err) // reject the promise
      })
    })
  },
```

Our login form doesn't show any message if we submit an invalid username/password combination, so we will have to handle this later.

One other things to mention is that we have not implemented a user profile, so we don't have anything for `USER_REQUEST`. Recall that `USER_REQUEST` originally made a mock request to get user profile data. We can keep this mocked for now with this:

```js
const actions = {
  [USER_REQUEST]: ({commit, dispatch}) => {
    commit(USER_SUCCESS, {"name":"Brian", "title":"Admin"})
    // apiCall({url: 'user/me'})
    //   .then(resp => {
    //     commit(USER_SUCCESS, resp)
    //   })
    //   .catch(resp => {
    //     commit(USER_ERROR)
    //     // if resp is unauthorized, logout, to
    //     dispatch(AUTH_LOGOUT)
    //   })
  },
}
```

We can come back to this once we implement a user profile. Let's review the changes we made to sqreen.io authentication implementation. We have changed five files:

- `src/components/login/index.vue`
- `src/components/navigation/index.vue`
- `src/store/modules/auth.js`
- `src/store/modules/users.js`
- `src/utils/api.js`

### Login Component

Change `data` to default to `admin`/`password` for the login form:

```js
    data () {
      return {
        username: 'admin',
        password: 'password',
      }
    },
```

### Navigation Component

Remove `{{ name }}` from the template. I have replaced it with `Welcome`:

```html
      <li v-if="isProfileLoaded">
        <router-link to="/account">Welcome</router-link>
      </li>
```

Remove `name` from computed properties:

```js
    computed: {
      ...mapGetters(['getProfile', 'isAuthenticated', 'isProfileLoaded']),
      ...mapState({
        authLoading: state => state.auth.status === 'loading',
        // name: state => `${state.user.profile.title} ${state.user.profile.name}`,
      })
    },
```

### `auth` module

Replace the original `apiCall` with our new call to the Django backend:

```js
      apiCall.post(
        '/api/auth/obtain_token/',
        user
      )
```

When we set `localStorage`, set the token to `resp.data.token`, not `resp.token`:

```js
        localStorage.setItem('user-token', resp.data.token)
```

Similarly, in `AUTH_SUCCESS`, set token in our state to `resp.data.token`, not `resp.token`:

```js
  [AUTH_SUCCESS]: (state, resp) => {
    state.status = 'success'
    state.token = resp.data.token
    state.hasLoadedOnce = true
  },
```

### `users` module

Remove the `apiCall` from the `USER_ACTION`, commit the `USER_SUCCESS` *mutation* with mock data and comment out the rest of the function:

```js
const actions = {
  [USER_REQUEST]: ({commit, dispatch}) => {
    commit(USER_SUCCESS, {"name":"User", "title":"Admin"})
    // apiCall({url: 'user/me'})
    //   .then(resp => {
    //     commit(USER_SUCCESS, resp)
    //   })
    //   .catch(resp => {
    //     commit(USER_ERROR)
    //     // if resp is unauthorized, logout, to
    //     dispatch(AUTH_LOGOUT)
    //   })
  },
}
```

Add `state.status = ""` to `AUTH_LOGOUT`:

```js
  [AUTH_LOGOUT]: (state) => {
    state.profile = {},
    state.status = ""
  }
```

### `api` module

Replace the mock API call with our own API to the Django backend using `axios`. Here we also add an interceptor so that each request attaches the token to it's header before it is sent:

```js
import axios from 'axios';
import store from '../store';

/* eslint no-unused-vars: ["error", { "args": "none" }] */
const apiCall = axios.create();

apiCall.interceptors.request.use(
  config => {
    // Do something before each request is sent
    if (store.getters.token) {
      // Attach a token to the header
      config.headers['JWT'] = store.token
    }
    return config
  },
  error => {
    // Do something with the request error
    Promise.reject(error)
  }
)

export default apiCall;
```

At this point we can commit our changes:

```
git add .
git commit -m "integrated our own backend into the sqreen.io authentication example"
```
