How to add authentication to your universal Nuxt app using nuxt/auth module?
Tags: javascript, vue
Published: 2019-09-30 17:05:50


![nuxt](http://codingfundas.com/content/images/2019/09/nuxt.png)

Recently I was working on a Nuxt.js app and had to add authentication to it. First thing I thought was to use vuex to store two fields in a state:

* __isLoggedIn__: a boolean representing whether user is logged in or not
* __loggedInUser__: an object containing the user details for the session that we get from server

And then I added a middleware on pages where I wanted to restrict access to logged in users only. The thought process for this approach is right but problem is that when you refresh the page, the state from vuex is lost. In order to handle that, you would need to use __localStorage__ but that would work only if your app is running in __spa__ mode, that is, on client side only. If you are running your app in __universal__ mode (server side rendered) then you will also need to use __cookies__ and write a custom middleware that checks whether it is running on client side or server side and then use __localStorage__ or __cookies__ accordingly. Doing all of this would be a good exercise to learn how everything works but adding it to a project where multiple people are working might not be a great idea in my opinion. Nuxt has an officially supported module just for this purpose. It's the [auth module](https://auth.nuxtjs.org/). In this post, I will talk about how to integrate the __auth module__ to your nuxt app to support authentication using __email__ and __password__. 

### Assumptions for the server API

We are making the assumption that the API server:

* Is running on __http://localhost:8080/v1__
* Uses cookie based sessions
* Has a JSON based API
* Has the following API endpoints:
    * __POST /v1/auth/login__: accepts __email__ and __password__ in request body and authenticates the user
    * __POST /v1/auth/logout__: does not need request body and deletes the user session from server
    * __GET /v1/auth/profile__: returns the logged in user's object

### Overview of the steps involved

We will divide this post into following steps:

* Installation of __axios__ and __auth__ modules
* Configuration needed in __nuxt.config.js__
* Using the state from auth module to check if user is logged in or not and accessing logged in user in our app components
* Using the auth module to authenticate the user using email and password based authentication
* Using middleware provided by the auth module to restrict access to pages to logged in users only

### Step 1: Install the axios and auth modules

Open the terminal, navigate to the root directory of your project and run the following command:

```
npm install @nuxtjs/auth @nuxtjs/axios
```

### Step 2: Configure axios and auth modules

Open your __nuxt.config.js__ file, find the __modules__ section and include the __axios__ and __auth__ modules and add their  configuration:

```
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/auth'
  ],

  auth: {
    strategies: {
      local: {
        endpoints: {
          login: {
            url: '/auth/login',
            method: 'post',
            propertyName: false
          },
          logout: { 
            url: '/auth/logout', 
            method: 'post' 
          },
          user: { 
            url: '/auth/profile', 
            method: 'get', 
            propertyName: false 
          }
        },
        tokenRequired: false,
        tokenType: false
      }
    }
  },
  
  axios: {
    baseURL: 'http://localhost:8080/v1',
    credentials: true
  },
  
```

The __auth__ object here includes the configuration. The __auth__ module supports __local__ strategy as well as __OAuth2__. Since we only have email and password based authentication in our case, we only need to provide the configuration for __local__ strategy. 

The __endpoints__ section is where we specify the details about our API server's endpoints for login, logout and logged in user's profile and each of the config looks like this:

```
  user: { 
    url: '/auth/profile', 
    method: 'get', 
    propertyName: false 
  }          
```

__url__ and __method__ should be consistent with your server API. The __url__ here needs to be relative to the __baseUrl__ config. The __propertyName__ tells the auth module which property in the response object to look for. For example, if your API server reponse for `GET /auth/profile` is like this:

```
{
  "user": {
    "id: 1,
    "name": "Jon Snow",
    "email": "jon.snow@asoiaf.com"
  }
}
```

Then you can set the __propertyName__ as `user` to look for only the `user` key in the API response. If you want to use the entire API response, you need to set __propertyName__ to `false`.

Since our API server has cookie based sessions, we are setting the __tokenRequired__ and __tokenType__ to `false`.

```
tokenRequired: false,
tokenType: false
```

For a complete list of options supported by the auth module, you can visit their official documentation [here](https://auth.nuxtjs.org/api/options.html#redirect)


The __axios__ object in the above config is used to provide the axios configuration. Here, we are setting the following properties:

```
  axios: {
    baseURL: 'http://localhost:8080/v1',
    credentials: true
  },
```

__baseUrl__ here is the root url of our API and any relative url that we hit using axios in our app will be relative to this url. Setting __credentials__ as `true` ensures that we send the authentication headers to the API server in all requests. 

### Step 3: Activate vuex store in your app

In order to use the auth module, we need to activate __vuex__ store in our application since that's where the session related information will be stored. This can be done by adding any __.js__ file inside the __store__ directory of your app and nuxt will register a namespaced vuex module with the name of the file. Let's go ahead and add a blank file called __index.js__ to the __store__ directory of our app. It's not mandatory to add __index.js__ file. You could have added any file for example __xyz.js__ in the __store__ directory and that would have activated vuex store in your app.

The auth module that we have included in our project will automatically register a namespaced module named __auth__ with the vuex store. And it has the following fields in the state:

* __loggedIn__: A boolean denoting if the user is logged in or not
* __user__: the user object as received from __auth.strategies.local.user__ endpoint configured in our __nuxt.config.js__ file.
* __strategy__: This will be `local` in our case

It also adds the necessary mutations for setting the state. So, even though we haven't created any __auth.js__ file in the __store__ directory of our app, the auth module has automatically taken care of all this. If it helps to understand, imagine that a file named __auth.js__ is automatically created by auth module in the __store__ directory of your app even though this file doesn't actually exists. This means that using __mapState__ on __auth__ module of your vuex store will work. For example, you can use this in any of your components or pages:

```
  computed: {
    ...mapState('auth', ['loggedIn', 'user'])
  },
```

Here is a complete example of a component using these properties:

```
<template>
  <b-navbar type="dark" variant="dark">
    <b-navbar-brand to="/">NavBar</b-navbar-brand>
    <b-navbar-nav class="ml-auto">
      <b-nav-item v-if="!loggedIn" to="/login">Login</b-nav-item>
      <b-nav-item v-if="!loggedIn" to="/register">Register</b-nav-item>
      <b-nav-item v-if="loggedIn" @click="logout">
        <em>Hello {{ user.name }}</em>
      </b-nav-item>
      <b-nav-item v-if="loggedIn" @click="logout">Logout</b-nav-item>
    </b-navbar-nav>
  </b-navbar>
</template>

<script>
import { mapState } from 'vuex'
export default {
  name: 'NavBar',
  computed: {
    ...mapState('auth', ['loggedIn', 'user'])
  },
  methods: {
    async logout() {
      await this.$auth.logout()
      this.$router.push('/login')
    }
  }
}
</script>

<style></style>

```

#### Alternative approach

Instead of using the __mapState__, you can also reference the __loggedIn__ and __user__ by __this.$auth.loggedIn__ and  __this.$auth.user__. So, in the above example, you could have re-written the computed properties as mentioned below and it would have still worked fine:

```
  computed: {
    loggedIn() {
      return this.$auth.loggedIn
    },
    user() {
      return this.$auth.user
    }
  },
```

### Step 4: Authenticating user using the auth module

We know how to use the auth module's APIs to check whether a user is logged in or not, or access the logged in user's details. But we haven't yet covered the part of how to authenticate the user. This is done by using the __this.$auth.loginWith__ method provided by the __auth__ module in any of your components or pages. The first argument to this function is the name of the strategy. In our case this will be `local`. It's an async function which returns a promise. Here is an example of how to use it:


```
  try {
    await this.$auth.loginWith('local', {
      data: {
        email: 'email@xyz.com'
        password: 'password',
      }
    })
    // do something on success
  } catch (e) {    
    // do something on failure 
  }

```

So, typically you would have a login page with a form with __email__ and __password__ fields mapped to __data__ of the component using __v-model__. And once you submit the form, you can run this function to authenticate using the __auth__ module. Here is an example of login page:

```
<template>
  <div class="row">
    <div class="mx-auto col-md-4 mt-5">
      <b-card>
        <b-form @submit="submitForm">
          <b-form-group
            id="input-group-1"
            label="Email address:"
            label-for="email"
          >
            <b-form-input
              id="email"
              v-model="email"
              type="email"
              required
              placeholder="Enter email"
            ></b-form-input>
          </b-form-group>

          <b-form-group
            id="input-group-2"
            label="Password:"
            label-for="password"
          >
            <b-form-input
              id="password"
              v-model="password"
              type="password"
              required
              placeholder="Enter password"
            ></b-form-input>
          </b-form-group>

          <b-button type="submit" variant="primary">Login</b-button>
        </b-form>
      </b-card>
    </div>
  </div>
</template>

<script>
export default {
  name: 'LoginPage',
  data() {
    return {
      email: '',
      password: ''
    }
  },
  methods: {
    async submitForm(evt) {
      evt.preventDefault()
      const credentials = {
        email: this.email,
        password: this.password
      }
      try {
        await this.$auth.loginWith('local', {
          data: credentials
        })
        this.$router.push('/')
      } catch (e) {
        this.$router.push('/login')
      }
    }
  }
}
</script>

<style></style>

```

In order to logout a logged in user, you can use the __this.$auth.logout__ method provided by the __auth__ module. This one doesn't need any arguments. Here is an example:

```
  methods: {
    async logout() {
      await this.$auth.logout()
      this.$router.push('/login')
    }
  }
```


### Step 5: Using auth middleware to restrict access to certain pages

The __auth__ module also provides middleware to restrict access to logged in users. So, for example if you want to restrict the __/profile__ route of your application to logged in users only, you can add the auth middleware to the __profile.vue__ page like this:

```
export default {
  name: 'ProfilePage',
  middleware: ['auth']
}
```

For more details on how you can configure your components and pages to use the `auth` middleware, you can check out the official docs [here](https://auth.nuxtjs.org/guide/middleware.html).

### Conclusion and References

This was kind of a getting started post for __axios__ and __auth__ modules with __NuxtJS__. We only covered the local strategy but the auth module also supports __OAuth2__ and can be used to support login using __Auth0__, __Facebook__, __Github__ and __Google__. I would definitely recommend checking out the __Guide__ and __API__ section of the auth module:

https://auth.nuxtjs.org/

The __axios__ module also provides us many configuration options. Although we didn't cover much of it in this post, but I would definitely recommend checking out the official docs for that as well:

https://axios.nuxtjs.org/

I hope this post was helpful in understanding the basics of auth module in Nuxt and makes it easier for you to navigate the rest of the official documentation on your own.

Happy coding :-)