How to build a Single Page Application using Vue.js, Vuex, Vuetify, and Firebase (Part 4 of 4)
Tags: vue, vuex, vuetify, javascript
Published: 2019-07-20 19:19:52

---
title: How to build a Single Page Application using Vue.js, Vuex, Vuetify, and Firebase (Part 4 of 4)
published: true
description: How to build a Single Page Application using Vue.js, Vuex, Vuetify, and Firebase (Part 4 of 4)
canonical_url: https://www.jenniferbland.com/spa-application-using-vue-js-vuex-vuetify-and-firebase-part-4/
cover_image: https://res.cloudinary.com/ratracegrad/image/upload/v1563809446/VuePt4_hqbehz.png
series: How to build a Single Page Application using Vue.js, Vuex, Vuetify, and Firebase
tags: #vue, #vuex, #vuetify, #javascript
---

Learn how to create a meal delivery website using Vue.js, Vuex, Vue Router, and Firebase.

This is part four of my four-part series on building a Vue application. Here is a list of all the parts:

[Part 1: Installing Vue and Building an SPA using Vuetify and Vue Router](https://dev.to/ratracegrad/how-to-build-a-single-page-application-using-vue-js-vuex-vuetify-and-firebase-part-1-of-4-3a63)

[Part 2: Using Vue Router](https://dev.to/ratracegrad/how-to-build-a-single-page-application-using-vue-js-vuex-vuetify-and-firebase-part-2-of-4-3pj6)

[Part 3: Using Vuex and accessing API](https://dev.to/ratracegrad/how-to-build-a-single-page-application-using-vue-js-vuex-vuetify-and-firebase-part-3-of-4-3k3p)

[Part 4: Using Firebase for Authentication](https://dev.to/ratracegrad/how-to-build-a-single-page-application-using-vue-js-vuex-vuetify-and-firebase-part-4-of-4-51hh)

Recap
-----

In the first part of this series, we created our Vue application using the Vue CLI. Also, we added Vuetify to the app. We used Vuetify to style our home page.

In the second part, we used Vue Router to add navigation between the different pages of our app. We added components for all the pages in our application.

In the third part, we were introduced to Vuex. We signed up for an API to provide recipes and used axios to retrieve them. This data was stored in the Vuex store which made it accessible to every component in the application.

What is Firebase?
-----------------

Firebase is a real-time cloud infrastructure for client-side apps. Firebase can turn any _Frontend_ application into a full-stack product capable of scaling infinitely in the cloud. It abstracts away most of your complex server-side features like user authentication, data persistence, file storage, and microservices, so you can focus on building an awesome experience for the end user.

The first step is to go to [firebase and create a new account](https://firebase.google.com). Log in to the account that you created. You will see this dashboard:

![Firebase Demo](https://res.cloudinary.com/ratracegrad/image/upload/v1563798716/demo_nue1c0.png) 

Click the `Add Project` button. Enter a name for your project. I entered “meal-prep” for the name of my project. Check all checkboxes. Then click the `create project` button.

![ Add new project dialog on Firebase](https://res.cloudinary.com/ratracegrad/image/upload/v1563798790/add_jradvn.png)

Once your project is created, Firebase will take you to your project’s home page.

![Project Home Page](https://res.cloudinary.com/ratracegrad/image/upload/v1563798820/project_miepsp.png) 

We need to integrate our project’s configuration into our meal-prep application. Click on the web button to add Firebase to your application. (NOTE: if you are not sure which button that it, it is the button with the `</>`. In the image above, the button is right above the words “get started.” Click the copy button to copy the snippet to your clipboard.

![Firebase config snippet ](https://res.cloudinary.com/ratracegrad/image/upload/v1563798857/config_mamnkn.png) 

Next, we need to incorporate this snippet into our meal prep application. You can initialize your firebase application in the `main.js` file. You can do it in the `App.vue` file. 

Instead, we are going to create a new directory called firebase in the src folder. Inside this new directory create a file called `index.js`. Paste the contents of your clipboard into this file. Remove the two lines with the `script` tags. In the first line of the file import firebase. On the last line initialize firebase. Your file should look like this:

```html
import firebase from 'firebase';

const config = {
    apiKey: "<youKeyHere>",
    authDomain: "<youKeyHere>",
    databaseURL: "<youKeyHere>",
    projectId: "<youKeyHere>",
    storageBucket: "<youKeyHere>",
    messagingSenderId: "<youKeyHere>"
};
firebase.initializeApp(config);
```
  

We are importing firebase from an npm package that we have not installed yet. Let’s install it now. In your terminal install firebase with this command:

```npm install firebase --save```

Now that we have installed firebase and created a config file, we need to add this file to our application so Vue is aware of it. Open up the `main.js` file and import in the config file we created. Here is what my `main.js` file looks like:


```html
import '@babel/polyfill';
import Vue from 'vue';
import './plugins/vuetify';
import App from './App.vue';
import router from './router';
import store from './store';
import '@/firebase/';

Vue.config.productionTip = false;

new Vue({
    router,
    store,
    render: h => h(App)
}).$mount('#app');
```
Go back to your firebase console in the browser. Click on `Authentication`. Click on the `set up sign-in method` button.

![Setting up authentication in firebase](https://res.cloudinary.com/ratracegrad/image/upload/v1563798910/auth_wa5hoi.png) 

In the list of sign-in providers, click on Email/Password:

![select Email/Password](https://www.jenniferbland.com/wp-content/uploads/listof.png)

Enable the option to all users to sign up using their email address and password. Then click the `save` button.

![Enable sign up using email and password](https://res.cloudinary.com/ratracegrad/image/upload/v1563798955/listof_ndmbos.png)  

Creating Sign Up Form
---------------------

In a previous post, we stubbed out the Join.vue and Signin.vue files. These two files will have almost the same code. We will create the Join form first. When we are finished we will copy/paste it into the Signin form.

Open the Join.vue component. You can remove everything that is in the template. Vuetify has a default layout structure for components. It flows like this:

*   v-container
*   v-layout
*   v-flex

So let’s create that layout now in the component. The start of our file looks like this:

```html
<template>
    <v-container fill-height>
        <v-layout align-center justify-center>
            <v-flex xs12 sm8 md4>

            </v-flex>
        </v-layout>
    </v-container>
</template>
```
  

For the `v-container` we are adding `fill-height`. We add this so that it centers the form vertically in the window. For the `v-flex` we add `xs12` `sm8` and `md4` values. This is similar to Bootstraps column width definition. On extra-small devices, the form will take up all 12 columns meaning the whole screen. On small devices, the form will be 3/4 of the screen wide. On medium and large screens the form will be 1/3 of the screen.

Inside the `v-flex` we are going to use a `v-card`. We add `class=”elevation-12"` to the `v-card` so that it appears to be floating above the page. For the top of the form, we will use a `v-toolbar`. We give it a color of `primary`. For the default installation of Vuetify the primary color is blue. We want the text in the toolbar to be white text instead of the default black. To turn the text white we add `dark` to the `v-toolbar`.

Next, we have a `v-card-text`. Inside of it, we have a `v-form`. For the form we are giving it a reference with the name of `form`. We are assigning it to the `v-model` with a value of `valid`. 

The last thing we add is `lazy-validation`. Our form needs to capture the user’s email and password. We will use two `v-text-field` to capture these values. To make things look better I have prepended an icon for each field. Each field has a `v-model` and `rules`. 

Before the form is submitted the field will be validated against all rules that are defined. If they pass then you can submit the form. We will take advantage of this when the user clicks the Join button. 

The last item to add to the form is a button. We add a `v-card-actions` and add a button. Here is what the template looks like for our component:

```html
<template>
    <v-container fill-height>
        <v-layout align-center justify-center>
            <v-flex xs12 sm8 md4>
                <v-card class="elevation-12">
                    <v-toolbar dark color="primary">
                        <v-toolbar-title>Join Form</v-toolbar-title>
                    </v-toolbar>
                    <v-card-text>
                        <v-form ref="form" v-model="valid" lazy-validation>
                            <v-text-field prepend-icon="person" name="email" label="Email" type="email"
                                          v-model="email" :rules="emailRules" required>
                            </v-text-field>
                            <v-text-field prepend-icon="lock" name="password" label="Password" id="password"
                                          type="password" required v-model="password" :rules="passwordRules">
                            </v-text-field>
                        </v-form>
                    </v-card-text>
                    <v-card-actions>
                        <v-spacer></v-spacer>
                        <v-btn color="primary" :disabled="!valid" @click="submit">Join</v-btn>
                    </v-card-actions>
                </v-card>
            </v-flex>
        </v-layout>
    </v-container>
</template>
```
  

We defined several models in our template. We need to add them to the `data` section of our script. In the script add a data object. We will add valid, email, password, emailRules and passwordRules. 

Email and password will contain the values the user inputs into the two text fields. Valid will tell if our form has passed all the rules we have created. For email, we check to make sure that the field is not empty. We also check that the contents match a basic RegExp to validate the email address. For password, we check to make sure the field is not empty. We also check to make sure the password is at least six characters in length.

Here is what the data object looks like now:

```html
data() {
    return {
        valid: false,
        email: '',
        password: '',
        emailRules: [
            v => !!v || 'E-mail is required',
            v => /.+@.+/.test(v) || 'E-mail must be valid'
        ],
        passwordRules: [
            v => !!v || 'Password is required',
            v =>
                v.length >= 6 ||
                'Password must be greater than 6 characters'
        ]
    };
},
```

The last thing we need to add is methods. In methods, we have `submit()`. This method will validate our form first. If it passes validation then it will call an action in our Vuex store called `userJoin`. We pass it the email and password the user entered in the form.

Here is what the methods look like:

```html
methods: {
    submit() {
        if (this.$refs.form.validate()) {
            this.$store.dispatch('userJoin', {
                email: this.email,
                password: this.password
            });
        }
    }
}
```


Creating userJoin Action in Vuex
--------------------------------

Open up the `store.js` file. We will create a new action called `userJoin`. By default the first parameter passed to this action is `context`. I will use object destructuring to get just `commit` from `context`. Commit is how I will call my mutation.

I will be using firebase to create the new user in the firebase database. To be able to use firebase in the store, I will need to import it. At the top of the file import firebase with this command:

```import firebase from 'firebase';```

Firebase authentication provides a method called `createUserWithEmailAndPassword`. We will pass the user’s email and password into this method. If it succeeds in registering the user it will return a user object. When it succeeds we will call two mutations: `setUser` and `setIsAuthenticated`. Here is what the action looks like:

```html
userJoin({ commit }, { email, password }) {
    firebase
        .auth()
        .createUserWithEmailAndPassword(email, password)
        .then(user => {
            commit('setUser', user);
            commit('setIsAuthenticated', true);
        })
        .catch(() => {
            commit('setUser', null);
            commit('setIsAuthenticated', false);
        });
}
```

This action calls two mutations. So let’s create then now. In mutations add a new mutation called `setUser`. Set the state value of user to the payload. Next, create a second mutation called `setIsAuthenticated`. Set the state value of isAuthenticated to the payload. Here is what the two mutations look like:

```html
setUser(state, payload) {
    state.user = payload;
},
setIsAuthenticated(state, payload) {
    state.isAuthenticated = payload;
}
```
  

In state, we need to add two new value: `user` and `isAuthenticated`. Here is what state looks like now:

```html
state: {
    recipes: \[\],
    apiUrl: 'https://api.edamam.com/search',
    user: null,
    isAuthenticated: false
},
```
  

Test Adding a New User
----------------------

Start your server with the command `npm run serve`. Click on the `Join` button in the navigation. Enter your email and a password and click the join button. When you click the button nothing visible happens. To verify that the user was registered, go the firebase console in your browser. Click on `Authentication`. You should see a list of users that have been registered for your application. Here you can see that the user I just registered was created.

![User has been registered](https://res.cloudinary.com/ratracegrad/image/upload/v1563799054/registered_wp8suw.png) 

We need to notify the user that they have been successfully created. We will do this but later. First, we are going to copy and paste the contents of the Join.vue component into the Signin.vue component. There are only two changes you will need to make in the template. Change the title to “Login Form.” For the button make the text say “Login.” In the submit method have it dispatch to `userLogin`. That’s it. You have now created both the Join and Login forms.

We need to create the action for Login. Open up the `store.js` file. Create a new action called userLogin. We will use firebase to login the user. Firebase provides a method called `signInWithEmailAndPassword`. We will call this method and pass in the user’s email and password they entered into the form. If the user entered their email and password correctly then we will call the two mutations `setUser` and `setIsAuthenticated`. Here is what the `userLogin` action looks like:

```html
userLogin({ commit }, { email, password }) {
    firebase
        .auth()
        .signInWithEmailAndPassword(email, password)
        .then(user => {
            commit('setUser', user);
            commit('setIsAuthenticated', true);
        })
        .catch(() => {
            commit('setUser', null);
            commit('setIsAuthenticated', false);
        });
},
```
  

Redirecting to Profile
----------------------

When a user successfully registers or login, we want to redirect them to their profile. When we created our app initially the Vue CLI 3 it created two routes for us. Those routes were `/` and `/about`. Eventually, the profile will contain a list of all recipes that the user has ordered from the `menu` page. Remember the button we put at the bottom of every recipe? That button will add the recipe to the user’s profile and store it in the database in firebase.

To redirect the user to the profile we will first import router at the top of the store.js file. The router is imported with the command:

```import router from '@/router';```

  

Next, in both actions we redirect the user to /about if they successfully register or login. You can do the redirection with this command:

```router.push('/about');```

  

If the user fails to register an account or login successfully we will redirect the user to the home page. _(NOTE: in a perfect scenario we will provide some notice to the user why the registration or login failed). You can redirect them to the home page with this command:_

```router.push('/');```

  

To test the redirection, start your server and click on the Login button. Enter the email and password you used when you created your user account. Click the Join button. If everything worked successfully you should be redirected to the About page.

Updating the navigation
-----------------------

The navigation has buttons for `Sign In` and `Join`. When a user successfully registers or login we would like to hide these two buttons. In their place, we want to show a `Logout` button.

Open up the `AppNavigation` component. We are going to group the two current buttons in a div. We are going to remove the class to hide the buttons on small and extra-small devices. Instead, we will place this class on the div. We add a `v-if` to the div to only show if the user is currently not authenticated. Below the `div` we will add a new button for Logout. This new button will have a style of outline with a color of white. When you click on this button it will call the method `logout`. We add a v-else to this button to show when the user is authenticated.

Next, add a method called `logout`. This method will call an action in our store called `userSignOut`.

We also need to add a new computed property called `isAuthenticated`. This property returns the value of isAuthenticated in the state of our store.

Here is what your AppNavigation should look like:

```html
<template>
    <span>
        <v-navigation-drawer app v-model="drawer" class="brown lighten-2" dark disable-resize-watcher>
            <v-list>
                <template v-for="(item, index) in items">
                    <v-list-tile :key="index">
                        <v-list-tile-content>
                            {{item.title}}
                        </v-list-tile-content>
                    </v-list-tile>
                    <v-divider :key="\`divider-${index}\`"></v-divider>
                </template>
            </v-list>
        </v-navigation-drawer>
        <v-toolbar app color="brown darken-4" dark>
            <v-toolbar-side-icon class="hidden-md-and-up" @click="drawer = !drawer"></v-toolbar-side-icon>
            <v-spacer class="hidden-md-and-up"></v-spacer>
            <router-link to="/">
                <v-toolbar-title to="/">{{appTitle}}</v-toolbar-title>
            </router-link>
            <v-btn flat class="hidden-sm-and-down" to="/menu">Menu</v-btn>
            <v-spacer class="hidden-sm-and-down"></v-spacer>
            <div v-if="!isAuthenticated" class="hidden-sm-and-down">
                <v-btn flat to="/sign-in">SIGN IN</v-btn>
                <v-btn color="brown lighten-3" to="/join">JOIN</v-btn>
            </div>
            <v-btn v-else outline color="white" @click="logout">Logout</v-btn>

        </v-toolbar>
    </span>
</template>

<script>
export default {
    name: 'AppNavigation',
    data() {
        return {
            appTitle: 'Meal Prep',
            drawer: false,
            items: \[{ title: 'Menu' }, { title: 'Sign In' }, { title: 'Join' }\]
        };
    },
    computed: {
        isAuthenticated() {
            return this.$store.getters.isAuthenticated;
        }
    },
    methods: {
        logout() {
            this.$store.dispatch('userSignOut');
        }
    }
};
</script>

<style scoped>
a {
    color: white;
    text-decoration: none;
}
</style>
```
  

We need to add the getter and action we just defined. Open up the `store.js` file. Create a new action called `userSignout`. This action will use firebase.auth() to sign the user out. After signing the user out, it sets the state variables `user` to null and `isAuthenticated` to false. Here is the `userSignout` method in the store:

```html
userSignOut({ commit }) {
    firebase
        .auth()
        .signOut()
        .then(() =&gt; {
            commit('setUser', <em class="markup--em markup--pre-em">null</em>);
            commit('setIsAuthenticated', <em class="markup--em markup--pre-em">false</em>);
            router.push('/');
        })
        .catch(() =&gt; {
            commit('setUser', <em class="markup--em markup--pre-em">null</em>);
            commit('setIsAuthenticated', <em class="markup--em markup--pre-em">false</em>);
            router.push('/');
        });
}
```
  

Next, we need to add a `getters` section to the store object. The `isAuthenticated` getters method will return true or false based on user authentication. Here is what the `getters` section of the store looks like:

```html
getters: {
    isAuthenticated(state) {
        <em class="markup--em markup--pre-em">return </em>state.user !== <em class="markup--em markup--pre-em">null </em>&amp;&amp; state.user !== <em class="markup--em markup--pre-em">undefined</em>;
    }
}
```
  

Adding Recipes to Database
--------------------------

Once a user is logged in they can click on any recipe to add it to their account. Their recipes will be shown in their profile which is the `/about` route. We need a database to store these recipes. Go to your firebase console in the browser. Click on `database` in the left side navigation panel. On the next screen you will see buttons to create a realtime database or a cloud firestore database. Make sure you create a new realtime database. In the dialog make sure you select to `start in test mode`. Then click the `enable` button.

![Start database in test mode](https://res.cloudinary.com/ratracegrad/image/upload/v1563799160/startdb_geyf8g.png)   

Now we want to store the user’s recipes in the database. Open up the MealPlans component. If a user tries to order a recipe and they are not logged in then we should redirect them to the login page. So let’s take care of that now. On the `Order` button add an @click that calls the method orderRecipe. Be sure to pass in `item` as an argument to the method. Your button should look like this:

```html
<v-card-actions>
    <v-btn color="green" dark @click="orderRecipe(item)">Order</v-btn>
</v-card-actions>
```
  

Before we create our method, we will create a computed value for isAuthenticated. This is the exact same code we used in `AppNavigation` earlier to show and hide the login and logout button correctly. Add a computed isAuthenticated. It should look like this:

```html
export default {
    name: 'MealRecipes',
    computed: {
        recipes() {
            return this.$store.state.recipes;
        },
        isAuthenticated() {
            return this.$store.getters.isAuthenticated;
        }
    }
};
```
  

Now we are ready to create our orderRecipe method. Add this method and its parameter. In this method, we want to first check if the user is logged in or not. If they are not we want to redirect them to `/sign-in` . If they are signed in then we want to call an action in the Vuex store that will append the recipe to the user account in the database. Here is what our method looks like:

```html
methods: {
    orderRecipe(item) {
        if (this.isAuthenticated) {
            this.$store.dispatch('addRecipe', item);
        } else {
            this.$router.push('/sign-in');
        }
    }
}
```
  

Open up the store.js file. We need to create a new action to add recipes. In this action, we are going to use firebase to add the recipe to a database called `users`. When the user was registered in firebase they were assigned a unique userid. We will be using this `uid` to store the name of the recipe in the database. In this action, we will be using `state` to get the value of the currently selected user. The `user` in `state` is an object. That object has a key called user. In that object, we will find the `uid`. We use that to push the title of the selected recipe into the database. Here is the action:

```html
addRecipe({ state }, payload) {
    firebase
        .database()
        .ref('users')
        .child(state.user.user.uid)
        .push(payload.label);
}
```
  

Now start your server and log in. Select a diet from the menu page. Then order a couple of recipes. The recipes you ordered should be shown in the database in firebase.

![Recipes added to the database](https://res.cloudinary.com/ratracegrad/image/upload/v1563799226/recipes_c635rt.png) 

Now that we have the recipes added to the database, we actually need to display them on the profile page for the user. Open up the `About.vue` file. Whenever this page is loaded it should fetch all the user’s recipes. To do this we add `mounted()` in our script. This will call a method called `getRecipes`.

Let’s create that method now. In the method, we are going to call an action in our Vuex store that will get all the user’s recipes. We have not created this action in the store yet but in simple terms, this action will get the user’s recipes. Then it will store them in a variable in `state` called `userRecipes`. Before we leave About.vue, add a computed property for `userRecipes`. This will return the `userRecipes` from `state` in our store. This is what About.vue script should look like:

```html
export default {
    name: 'About',
    computed: {
        userRecipes() {
            return this.$store.state.userRecipes;
        }
    },
    mounted() {
        this.getRecipes();
    },
    methods: {
        getRecipes() {
            this.$store.dispatch('getUserRecipes');
        }
    }
};
```
  

Next, open up your `store.js` file. We need to create the `getUserRecipes` action. When the user logins we store a variable in `state` called user. This variable will have the unique user ID assigned to that user when it was registered in firebase. We want to get all the recipes in the users database that have this user ID. Once we get all the recipes we want to set userRecipes to contain them. Here is the getUserRecipes action:

```html
getUserRecipes({ state, commit }) {
    <em class="markup--em markup--pre-em">return </em>firebase
        .database()
        .ref('users/' + state.user.user.uid)
        .once('value', snapshot =&gt; {
            commit('setUserRecipes', snapshot.val());
        });
}
```
  

In our mutations, we need to add a `setUserRecipes`. It looks like this:

```html
setUserRecipes(state, payload) {
    state.userRecipes = payload;
}
```
  

We also need to add a `userRecipes` in `state`. We set its initial value to an empty array. Here is my entire state object:

```html
state: {
    recipes: \[\],
    apiUrl: 'https://api.edamam.com/search',
    user: <em class="markup--em markup--pre-em">null</em>,
    isAuthenticated: <em class="markup--em markup--pre-em">false</em>,
    userRecipes: \[\]
},
```
  

Now that we are getting the recipes we need to display them on the page to the user. So go back to your `About.vue` file. In the template, we are going to loop through all the user’s recipes and display them. I am going to show you my code for the template first then explain what I have done:

```html
<template>
    <v-container >
        <v-layout column>
            <h1 class="title my-3">My Recipes</h1>
            <div v-for="(item, idx) in userRecipes" class="subheading mb-2" :key="idx">
                {{item}}
            </div>
        </v-layout>
    </v-container>
</template>
```
  

I have set the layout to be `column`. I did this because I want each recipe to be listed on the page. To make things look clearer I have added a title. I added my-3 to add margin-top and margin-bottom so that there is spacing between the title and the list of recipes. Next, I looped through each recipe and display it. This is what the user sees if they have recipes:

![List of my recipes](https://res.cloudinary.com/ratracegrad/image/upload/v1563799327/listRecipes_x31wwl.png) 

This is great but when if a user logs in and they do not have any recipes? They see the title “My Recipes” and a blank page. This is not a user-friendly design. So let’s change it to display something more friendly. We will display a button that will take the user to the `menu` page. In our template, we will add this button. To make the button redirect to the menu page we can add `to=”/menu”` to the button. Here is my final template for the `About.vue` component.

```html
<template>
    <v-container >
        <v-layout column>
            <h1 class="title my-3">My Recipes</h1>
            <div v-for="(item, idx) in userRecipes" class="subheading mb-2" :key="idx">
                {{item}}
            </div>
            <v-flex mt-4>
                <v-btn color="primary" to="/menu">Go To Menu</v-btn>
            </v-flex>
        </v-layout>
    </v-container>
</template>
```
  

Showing Profile in Navigation
-----------------------------

The last thing we need to add is the ability to show a link to the profile in the navigation. Just like the logout button, this should only be shown if the user is authenticated. Open up the AppNavigation components. We are going to group the profile button and the logout button in a div. This is the same thing we did earlier for the `Sign In` and `Join` buttons. Add a div and move the logout button to be inside this div. Add another button for `profile`. This button will be flat just like the `Sign In` button. Here is what my AppNavigation looks like now:

```html
<template>
    <span>
        <v-navigation-drawer app v-model="drawer" class="brown lighten-2" dark disable-resize-watcher>
            <v-list>
                <template v-for="(item, index) in items">
                    <v-list-tile :key="index">
                        <v-list-tile-content>
                            {{item.title}}
                        </v-list-tile-content>
                    </v-list-tile>
                    <v-divider :key="\`divider-${index}\`"></v-divider>
                </template>
            </v-list>
        </v-navigation-drawer>
        <v-toolbar app color="brown darken-4" dark>
            <v-toolbar-side-icon class="hidden-md-and-up" @click="drawer = !drawer"></v-toolbar-side-icon>
            <v-spacer class="hidden-md-and-up"></v-spacer>
            <router-link to="/">
                <v-toolbar-title to="/">{{appTitle}}</v-toolbar-title>
            </router-link>
            <v-btn flat class="hidden-sm-and-down" to="/menu">Menu</v-btn>
            <v-spacer class="hidden-sm-and-down"></v-spacer>
            <div v-if="!isAuthenticated" class="hidden-sm-and-down">
                <v-btn flat to="/sign-in">SIGN IN</v-btn>
                <v-btn color="brown lighten-3" to="/join">JOIN</v-btn>
            </div>
            <div v-else>
                <v-btn flat to="/about">PROFILE</v-btn>
                <v-btn outline color="white" @click="logout">Logout</v-btn>
            </div>

        </v-toolbar>
    </span>
</template>
```
  

Adding Route Guards
-------------------

Currently, the user can navigate to the profile page by typing it into the URL of the browser We don’t want to let users do this if they are not logged in. Vue Router provides the ability to add route guards before navigating to a URL. We want to test if a user is authenticated before allowing them to redirect to the `/about` page.

Open up the `router.js` file. Route guards work in conjunction with meta tags. Find the `/about` route. We will add a `authRequired` meta tag to it. The route should look like this:

```bash
{
    path: '/about',
    name: 'about',
    component: () =&gt; <em class="markup--em markup--pre-em">import</em>('./views/About.vue'),
    meta: {
        authRequired: <em class="markup--em markup--pre-em">true
    </em>}
},
```
  

Route guards are checked in a method called beforeEach that is part of Vue Router. This method is passed three parameters:

*   the route you are going to
*   the route you came from
*   a next method that continues with the current route

Our beforeEach method will check every route that we are going to to see if it contains the meta tag of authRequired. If it does, it will check to see if the user is Authenticated. If the user is not authenticated it will redirect them to the `/sign-in` page. If the user is logged in then it will allow the route to proceed. If a user routes to any page that does not have the authRequired meta tag then the route will proceed. Here is the method I have added to my router to do this checking:

```html
router.beforeEach((to, from, next) =&gt; {
    <em class="markup--em markup--pre-em">if </em>(to.matched.some(record =&gt; record.meta.authRequired)) {
        <em class="markup--em markup--pre-em">if </em>(!store.state.user) {
            next({
                path: '/sign-in'
            });
        } <em class="markup--em markup--pre-em">else </em>{
            next();
        }
    } <em class="markup--em markup--pre-em">else </em>{
        next();
    }
});
```
  

Get the Code
------------

Even though this is a 4-part series, you can get the [finished code in my GitHub account.](https://github.com/ratracegrad/meal-prep) Please help me out and **star the repo** when you get the code.

Summary
-------

In this part of this series, you have learned:

*   What is firebase
*   Using firebase to authenticate users who sign in with email and password
*   Using firebase to store the recipes a user has ordered
*   Using route guards to not users access pages if they are not authenticated
*   Display user’s list of recipes from the database on firebase


Training Courses
-----------------
I create training courses on my website CodePrep. I have training courses on Vue, Webpack, Flexbox, functional programming and more. [Check it out here.](https://codeprep.io/ "CodePrep")