Vue.js - Structuring & Authentication In 2019 (Part-2)

Note:, This is the next sequel of our Vue.js series. In our previous article we discussed about how to get started with the Vue.js. If you haven't read the other articles, do give a read.

Part 1 - Getting Started With Vue.js

Part 3 - Making CRUD App in Vue.js

Today, in the menu we have something delicious for you,

  1. We will first understand the directory structure of the Nuxt.js application.

  2. Then will see the authentication, kinda login register thing in simple terms.

Note: Still wondering why I am not going to basic vue-cli then read the part 1. So, I hope everybody has setup the basic Nuxt project, I am going with the SPA(Single Page Application) not Universal, and also the axios(would use for network calls), make sure you chosen that options correctly while doing the setup of the Nuxt app.

Directory Structure

If you been working around frameworks, so would find all of them have certain directory structure — Laravel, Django, Angular etc and if they don’t have that, community come up with there own solutions like React.js which soon turns to be trend and everybody follows. So, here the same case with the Nuxt.js

So, let’s go one by one and see what each file and folder here is doing, there might be some files which might not be present or extra as per different options you have chose while installing Nuxt.js, but yeah the directory structure gonna same.

So, let’s start from the top

  1. Assets - As the name suggests it contains the un-compiled assets such as css files, sass, images, fonts etc.

  2. Components - If you have worked earlier with some modern javascript frameworks like React.js, you are aware of this term. They are the basic unit or I can say the basic building block which will align themselves to make a complete page.

  3. Layouts - The look and feel of the website is defined in layouts, keeping the basic structure same.

  4. Middleware - Is very know term around the developer, so what are they? They are the middlemen of the things I can say, like they happen or occur before doing something and what role middleware will play here?, they might load before rendering page or group of pages.

  5. Pages - They are the actual page which we will see on the browser.

    Note: One thing regarding the Nuxt.js which is not present in the vue-cli i.e for maintaining the routes, you have to maintain a separate file router.js or something. Nuxt.js have its own solution, with the help of which the routes are automatically generated with the page name and directory structure in the pages directory, there are more things about these automatically generated routes as we move on.

  6. Plugins - Contains javascript plugins like vuetify, which you want to run before your application.

  7. Static - Don’t confuse it with the assets, assets directory are the uncompiled assets, they will be used in the Vue.js app compilations. Whereas static directory is something out of the Nuxt app directory, which get maps to the server root, and is useful to put any static content like image, text file etc. Eg. /static/img.jpg will open to the https://xyz.com/img.jpg url.

  8. Store - A store is whole state tree of your application that help to access a data on any page as all the changes are made in the same state object.

    Note: Don’t worry if you are getting confuse. In-fact, first when I am reading state, it’s will be difficult to digest some concepts so i will make separate article around the store and the vuex. If you having a background of React.js you also see a store there, precisely redux store. So, imagine vuex a replica or that as of now. Although it has something more and those who are not aware of the redux.

  9. Nuxt.config.js - Contains the basic configuration of the Nuxt project. The file contains modules, plugins, basic html structure of our app. You can check our nuxt.config.js here.

  10. The rest of files are general configuration and npm project files.

Authentication

If you see the meaning of the word authenticate, it means true, original, genuine. Authentication in our context is the verification of the credentials of the connection attempt. Similar to what we see on facebook, twitter etc.

There are various authentication mechanism like Basic Auth, JWT Auth, Digest Auth, OAuth 1.0, OAuth2.0 etc. and different people use different authentication as per their needs. We don’t go deep into the auth mechanism as its out of scope of this article.

For this article we will use JWT(JSON web token) based authentication which generates a token hashed by KEY with a time expiry, that can be encoded and decoded by the KEY until the token is valid. To know more about JWT read here.

Moreover JWT has library implementations around most of the programming languages.

Prerequisite - We are using these end points for authentication https://documenter.getpostman.com/view/2900929/S1a7Ujer?version=latest

We will first make a register screen, fill up registration details and submit the form which will hit the register api, which will give us the status 201 response and the user token in case of successful creation of the user.

Let’s start 🚀

Register

So, first make a register page in the pages directory.

<template>
<v-layout
    column
    justify-center
    align-center
  >
    <v-flex
      xs12
      sm8
      md6
    >
      <div class="text-xs-center">
        <logo />
        <vuetify-logo />
      </div>
      <v-card>
        <v-card-title class="headline">
          Register Here
        </v-card-title>
        <v-card-text>
          <form @submit.prevent="registerUser">
            <v-text-field
              label="Name"
              v-model="name"
              required
            ></v-text-field>
            <v-text-field
              label="Email"
              v-model="email"
              required
            ></v-text-field>
            <v-text-field
              label="Password"
              v-model="password"
              type="password"
              required
            ></v-text-field>
            <v-btn type="submit">
              Sign Up
            </v-btn>
            Already Have a account? Login <nuxt-link to="/login">
              here
            </nuxt-link>
          </form>
        </v-card-text>
      </v-card>
    </v-flex>
  </v-layout>
</template>
<script>

import Logo from '~/components/Logo.vue'
import VuetifyLogo from '~/components/VuetifyLogo.vue'
export default {
  components: {
    Logo,
    VuetifyLogo
  },
  data() {
    return {
      name: '',
      email: '',
      password: ''
    }
  },
}
</script>

If you observe that the template has the basic structure from the vuetify, and 3 fields are used in the registration api and mapped with the data in the script code via v-model. So any value you write in the form gets update in the data object or a Vue instance variables — (name, email, password). From this you obtain this kind of structure on the /register route.

Now, let’s write the function needed for calling the register user api. As told earlier we will use axios for network calls.

So, if the network call get a success it will return a token which we will we store in the session storage(you can store in the local storage, if you want to persists the token after the session).

Why we need token ?

We need token for further authentication, that token is need at the time of authenticated api calls like logout, getting user details it’s passed either as param or in header as bearer token.

One more thing you will observe , that we don’t need to import axios, nuxt as they have preloaded to the package. So, let’s write the function in the methods.

export default {
  components: {
    Logo,
    VuetifyLogo
  },
  data() {
    return {
      name: '',
      email: '',
      password: ''
    }
  },
  methods: {
    /**
     * [registerUser used to register the user]
     * @return {[type]} [none]
     */
    registerUser() {
      const { name, email, password } = this
      const data = { name, email, password }
      const URL = 'https://hidden-depths-47488.herokuapp.com/api/register'
      this.$axios({
        method: 'post',
        url: URL,
        headers: {
          Accept: 'application/json',
          Content: 'application/json'
        },
        data: data
      })
        .then(res => {
          sessionStorage.setItem('token', res.data.token)
          this.$router.push('/dashboard')
        })
        .catch(err => {
          // eslint-disable-next-line
          console.log(err)
        })
    }
  }
}

As we can see registerUser is the function called in form template which is defined as first function in methods and inside the registerUser, we are fetching the data that we need to pass for the register api call.

In the axios call you see, we mention the type of the request which is POST in our case, then headers have the other required configuration which already present in the documentation with example.

Next is .then which is an important step, if the api is successful that is we obtain a 2xx response, it picks the token store in the sessionStorage and the redirect us to dashboard page.

In case something went wrong, like wrong data or something or already registered user. You will receive in errors, right here i am just logging them ,instead them you might show them in a popup, alert, toast as you like.

Login

The login page is the exact clone of register page, just make a login.vue in the pages directory, I think you should leave the article for few mins and try to make it by yourself, although I have put the code of the login page too.

The only difference the login page is the absence of the name and try to show some alert in case of fail api, which means the email and password of the user are incorrect.

<template>
  <v-layout
    column
    justify-center
    align-center
  >
    <v-flex
      xs12
      sm8
      md6
    >
      <div class="text-xs-center">
        <logo />
        <vuetify-logo />
      </div>
      <v-card>
        <v-card-title class="headline">
          Login Here
        </v-card-title>
        <v-card-text>
          <form @submit.prevent="loginUser">
            <v-text-field
              v-model="email"
              label="Email"
              required
            />
            <v-text-field
              v-model="password"
              label="Password"
              type="password"
              required
            />
            <v-btn type="submit">
              Sign In
            </v-btn>
            Want to Register? Register <nuxt-link to="/register">
              here
            </nuxt-link>
          </form>
        </v-card-text>
      </v-card>
    </v-flex>
  </v-layout>
</template>
<script>
import Logo from '~/components/Logo.vue'
import VuetifyLogo from '~/components/VuetifyLogo.vue'
export default {
  components: {
    Logo,
    VuetifyLogo
  },
  data() {
    return {
      email: '',
      password: ''
    }
  },
  methods: {
    /**
     * [loginUser used to login the user]
     * @return {[type]} [none]
     */
    loginUser() {
      const { email, password } = this
      const data = { email, password }
      const URL = 'https://hidden-depths-47488.herokuapp.com/api/login'
      this.$axios({
        method: 'post',
        url: URL,
        headers: {
          Accept: 'application/json',
          Content: 'application/json'
        },
        data: data
      })
        .then(res => {
          sessionStorage.setItem('token', res.data.token)
          this.$router.push('/dashboard')
        })
        .catch(err => {
          alert('Wrong email/password')
          // eslint-disable-next-line
          console.log(err)
        })
    }
  }
}
</script>

and if you hit /login the page looks something like this

DashBoard and logout

Right now we are not adding too much to the dashboard, simple box showing the data fetched via the user details api and a logout button.

Might be in the next article or the article where I would be working around the crud application, I would showing how I am using the token in the header to authenticate my api calls.

Let’s create a dashboard.vue in our code, here’s the basic structure.

<template>
  <v-layout
    column
    justify-center
    align-center
  >
    <v-flex
      xs12
      sm8
      md6
    >
      <div class="text-xs-center">
        <logo />
        <vuetify-logo />
      </div>
      <v-card>
        <v-card-title class="headline">
          Welcome, {{ name }}
        </v-card-title>
        <v-card-text>
          <v-btn @click="logOut">
            Log out
          </v-btn>
          </form>
        </v-card-text>
      </v-card>
    </v-flex>
  </v-layout>
</template>
<script>
import Logo from '~/components/Logo.vue'
import VuetifyLogo from '~/components/VuetifyLogo.vue'
export default {
  components: {
    Logo,
    VuetifyLogo
  },
  data() {
    return {
      name: ''
    }
  }
}
</script>

We have a sample logout button and also a name variable to show the name of the user which we will fetch from the api.

Let’s first fetch the user details

<script>
import Logo from '~/components/Logo.vue'
import VuetifyLogo from '~/components/VuetifyLogo.vue'
export default {
  components: {
    Logo,
    VuetifyLogo
  },
  data() {
    return {
      name: ''
    }
  },
  mounted() {
    this.fetchUserDetails()
  },
  methods: {
    /**
     * [fetchUserDetails used to fetch user details]
     * @return {[type]} [none]
     */
    fetchUserDetails() {
      const token = sessionStorage.getItem('token')
      const URL = `https://hidden-depths-47488.herokuapp.com/api/user?${token}`
      this.$axios({
        method: 'get',
        url: URL,
        headers: {
          Accept: 'application/json'
        }
      })
        .then(res => {
          this.name = res.data.user.name
        })
        .catch(err => {
          // eslint-disable-next-line
          console.log(err)
        })
    }
  }
}
</script>

Here, you will see a mounted function, the basic detail I can tell about that it calls the fetchUserDetails function on the initial load of page, rest mounted function is the part of component lifecyle which calls when the vue component is mounted, we would cover this in separate article, giving a deeper insight over the life cycle of the vue component.

So, let’s focus on the api call, if you observe the api call we are using our stored JWT toke, although we are passing it as our param, but it’s helps to backend to identify the user, returning basic user details from which we store in the name of the user in the vue data which we display in the UI.

So, our screen would something look like this.

So, let’s work on the logout function, it’s quite straight forward, on that logout function call the logout api to invalidate the token, remove the token from sessionStorage and also route to the login page.

Let’s do it.

/**
     * [logOut used to logout user]
     * @return {[type]} [none]
     */
    logOut() {
      const token = sessionStorage.getItem('token')
      const URL = `https://hidden-depths-47488.herokuapp.com/api/logout?token=${token}`
      this.$axios({
        method: 'get',
        url: URL,
        headers: {
          Accept: 'application/json'
        }
      })
        .then(_ => {
          sessionStorage.removeItem('token')
          this.$router.push('/login')
        })
        .catch(err => {
          // eslint-disable-next-line
          console.log(err)
        })
    }

So, as I mentioned it’s quite simple, invalidating token, then removing from session and then moving to login url.

Note: Please refer to https://github.com/overflowjs-com/vue.js-authentication-part-2 to see the code and this webapp is active here - https://unruffled-goldstine-e8478d.netlify.com/

And we are done, If you found any error or you want articles regarding any specific problem or concept do mention in the comments.

Hope you like this article😍. Please share with other if you can, this motivate us to write more.

For more articles stay tuned to overflowjs.com

Checkout articles on Javascript, Angular, Node.js, Vue.js

Email

About Shubham Bansal

Shubham has been full stack developer/Engineer, building scalable systems for startups, also a tech freelancer remotely working with many organisations around the globe to make fault tolerant systems.

Subscribe to our email list

More Tags Of Your Interest