Working with Vue + Firebase Authentication

In this article, we are going to create a basic authentication with Firebase. Don’t worry if you are new to firebase, we are also going to cover how to create a project with Firebase and grab your web API keys. We are going to create Login, Sign Up, and a Dashboard route to figure out about the firebase authentication.

Setup App with Vue CLI

First, let’s create your project with Vue CLI. If you are familiar with CRA( create-react-app ) then the Vue CLI is similar to CRA to create your project boilerplate with almost zero effort.

npx @vue/cli create firebase-auth

This command will ask you to select a preset to set up your project that you can select either default or manually. We required vue-router to our firebase authentication app. So we are going to selec the manually preset.

Vue Project Structure

The manually preset will help you select more required options such as TypeScript, PWA, Router etc. You need to press the spacebar to select one of these options and up/down arrow key to handle to option. You need to select the Router as its required for our app.

Vue Manually Preset

Next, wait for a while until the process complete.

The next step is to create a basic template for Login, Sing Up, and Dashboard routes. We are going to use the bootstrap to quickly set up the layout for the further.

Add Bootstrap Framework to your app

First, let’s add the bootstrap CSS to a recently created project. We need the basic style, so don’t require to add the jQuery and Javascript dependencies for the bootstrap. We can add it through the npm command but to make this process quick, we are going to add it to the public/index.html file like below.

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">

Now, it’s time to create and define the routes and the layouts.

Create Navigation and Routes

First, open the App.vue file which is located under the project, and then /src directory.

<template>
    <div class="navbar navbar-dark bg-primary">
        <a class="navbar-brand" href="#">Firebase Auth</a>
        <ul class="nav">
            <li class="nav-item">
                <router-link class="nav-link text-white" to="/">Home</router-link>
            </li>
            <li class="nav-item">
                <router-link class="nav-link text-white" to="/dashboard">Dashboard</router-link>
            </li>
            <li class="nav-item">
                <router-link class="nav-link text-white" to="/login">Login</router-link>
            </li>
        </ul>
    </div>
    <div class="container py-4">
        <router-view />
    </div>
</template>

As you can see, we have defined the route links. Now let’s create 3 files under the /src/views directory i.e. Login.vue, Signup.vue and the Dashboard.vue and open the index.js file under /src/router directory and add the routes.

const routes = [
    {
        path: "/",
        name: "Home",
        component: Home
    },
    {
        path: "/login",
        name: "Login", 
        component: () => import("../views/Login.vue")
    },
    {
        path: "/signup",
        name: "Signup", 
        component: () => import("../views/Signup.vue")
    },
    {
        path: "/dashboard",
        name: "Dashboard", 
        component: () => import("../views/Dashboard.vue"),
        meta: {
            requiresAuth: true
        }
    }
];

As you can see in the above codes, that we have used the meta property for the Dashboard route to make the authentication required only for this route.

Now we have to check for the authentication required for every route. Now let’s use the navigation guard to add some conditional logic to check each route.

const router = createRouter({
    history: createWebHistory(process.env.BASE_URL),
    routes
});

router.beforeEach((to, from, next) => {
    const authenticatedUser = null;
    const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
    
    if ( requiresAuth && ! authenticatedUser ) {
        alert("You are not authorized to access this area.");
        next("login");
    }
    else {
        next();
    }
});

We have used the beforeEach() guard. For the time being, we are going to add null for the authenticatedUser variable, later we can use the firebase in place of null. Next, we are accessing the requiresAuth from the meta property from the currect route. And the final condition to display the alert for the unauthorized access and redirect the user to the login route if the user is not authenticated.

Now let’s give some rest for the logic part and move to the template section for Login.vue, Signup.vue and the Dashboard.vue views.

Let’s Create the Basic Layout

We don’t have much to explain the template section, because it’s just a plain HTML. If you want to HTML part then stay on this section or you can move to the next section.

Login.vue Template

Vue Firebase Login Layout
<template>
    <div class="row">
        <div class="col-12 text-center mb-4">
            <h1>Log In</h1>
        </div>
        <div class="col-sm-5 m-auto">
            <form id="login-form">
                <div class="row text-left">
                    <div class="col-sm-12 form-group">
                        <label for="email">Email Address</label>
                        <input type="email" id="email" class="form-control form-control-lg">
                    </div>
                    <div class="col-sm-12 form-group">
                        <label for="password">Password</label>
                        <input type="password" id="password" class="form-control form-control-lg">
                    </div>
                    <div class="col-sm-12 text-center form-group">
                        <button class="btn btn-lg btn-primary px-4">
                            <span>Login</span>
                        </button>
                    </div>
                    <div class="col-sm-12 text-center form-group mt-5">
                        <p>Don't have an account? <router-link to="/signup">Sign Up</router-link></p>
                    </div>
                </div>
            </form>
        </div>
    </div>
</template>

Signup.vue Template

Vue Firebase Signup Layout
<template>
    <div class="row">
        <div class="col-12 text-center mb-4">
            <h1>Sign Up</h1>
        </div>
        <div class="col-sm-5 m-auto">
            <form id="signup-form">
                <div class="row text-left">
                    <div class="col-sm-12 form-group">
                        <label for="email">Email Address</label>
                        <input type="email" id="email" class="form-control form-control-lg">
                    </div>
                    <div class="col-sm-12 form-group">
                        <label for="password">Password</label>
                        <input type="password" id="password" class="form-control form-control-lg">
                    </div>
                    <div class="col-sm-12 text-center form-group">
                        <button class="btn btn-lg btn-primary px-4">
                            <span>Sign Up</span>
                        </button>
                    </div>
                    <div class="col-sm-12 text-center form-group mt-5">
                        <p>
                            Already have an account? 
                            <router-link to="/login">Login</router-link>
                        </p>
                    </div>
                </div>
            </form>
        </div>
    </div>
</template>

Dashboard.vue Template

<template>
    <div class="row">
        <div class="col-12">
            <h1>Dashboard</h1>
        </div>
    </div>
</template>

We will come later to the vue project. Time to move to the Firebase part. If you don’t have an account with Firebase then create one or use your existing account details to get the console section.

Create Project with Firebase

We are using a fresh account with the Firebase and this what you can see after getting to the dashboard. So, let’s create your project/container for the app but clicking on the “Create a project” button.

Vue Firebase Welcome Screen

Next, give any suitable name for your project. Now click the “Create a project” button. and name your app whatever you like and press the “Continue” button.

Vue Firebase Create a Project Screen

The next screen will be asking to enable Google Analytics for this project. Currently, we don’t require this so Disable it and press the “Create Project” button.

Vue Firebase GA Screen 1
Vue Firebase GA Screen 2

It will take a very small time to prepare the project and press the “Continue” button once it ready to go.

Vue Firebase Continue Screen

Cool, we have successfully created our project in Firebase.

Add Firebase to our Web Application

Next, we have to access it to our application. As you can see from the below screenshot, Firebase supports multiple platforms to work with. So we have to select the Web Application platform.

Vue Firebase Project

Next, We have to add a suitable name and click the “Register app” button.

Vue Firebase Web App
Vue Firebase Register Web App

Firebase will provide you some mandatory configuration that you require to connect your web app with firebase. Copy the provides codes and paste it somewhere cause we are going to use it with our Vue app.

Vue Firebase Web API Key

Install Firebase to Vue App

We required to install the Firebase SDK to connect with our Vue app. So, let’s install it.

npm install firebase --save

Now open the main.js file and import firebase with the required configuration provided by Firebase.

import firebase from 'firebase';
....
....

// Your web app's Firebase configuration
var firebaseConfig = {
    apiKey: "AIzaxxxxxxxxxxxxxxxxxxxr14",
    authDomain: "vue-auth-xxxxx.firebaseapp.com",
    databaseURL: "https://vue-auth-xxxxxx.firebaseio.com",
    projectId: "vue-auth-xxxx",
    storageBucket: "vue-auth-xxxxx.appspot.com",
    messagingSenderId: "xxxxxxxx",
    appId: "1:xxxxxxx:web:9xxxxxxxxxxxxxx8"
};

// Initialize Firebase
firebase.initializeApp(firebaseConfig);

createApp(App)
  .use(router)
  .mount("#app");

Make sure to replace your configuration settings correctly.

Signup with Firebase

Now, let’s add the Firebase with Signup.vue template. First, let’s complete it by attaching the data model and event.

<template>
    <div class="row">
        <div class="col-12 text-center mb-4">
            <h1>Sign Up</h1>
        </div>
        <div class="col-sm-5 m-auto">
            <div v-if="errorMessage !== ''" class="alert alert-danger" role="alert">
                {{ errorMessage }}
            </div>
            <div v-if="successMessage !== ''" class="alert alert-success" role="alert">
                {{ successMessage }}
            </div>
            <form @submit.prevent="signupRequest" id="signup-form">
                <div class="row text-left">
                    <div class="col-sm-12 form-group">
                        <label for="email">Email Address</label>
                        <input type="email" id="email" v-model="email" class="form-control form-control-lg">
                    </div>
                    <div class="col-sm-12 form-group">
                        <label for="password">Password</label>
                        <input type="password" id="password" v-model="password" class="form-control form-control-lg">
                    </div>
                    <div class="col-sm-12 text-center form-group">
                        <button v-bind:disabled="xhrRequest" v-bind:class="{disabled: xhrRequest}" class="btn btn-lg btn-primary px-4">
                            <span v-if="! xhrRequest">Sign Up</span>
                            <span v-if="xhrRequest">Please Wait...</span>
                        </button>
                        <div v-if="xhrRequest" class="spinner-border text-secondary _loader" role="status">
                            <span class="sr-only">Loading...</span>
                        </div>
                    </div>
                    <div class="col-sm-12 text-center form-group mt-5">
                        <p>
                            Already have an account? 
                            <router-link to="/login">Login</router-link>
                        </p>
                    </div>
                </div>
            </form>
        </div>
    </div>
</template>
<script>
import firebase from "firebase";
export default {
    name: "Signup",
    data() {
        return {
            email: "",
            password: "",
            xhrRequest: false,
            errorMessage: "",
            successMessage: ""
        }
    }, 
    methods: {
        signupRequest() {}
    }
}
</script>
<style scoped>
._loader {
    position:relative;
    top:6px;
    left:10px;
}
</style>

We required the email, password, xhrRequest, errorMessage, and successMessage data model to working with. The email and password model we require for registering a user. The xhrRequest model to identify the async request made by Firebase. And the errorMesssage and successMessage for displaying the error or success message.

The signupRequest method we have attached with our Form to submit the email and password to the Firebase.

<form @submit.prevent="signupRequest" id="signup-form">

We have also used the binding to attach the CSS class to “Sign Up” button.

<button v-bind:disabled="xhrRequest" v-bind:class="{disabled: xhrRequest}" class="btn btn-lg btn-primary px-4">

The disabled property and the CSS class only works when the xhrRequest model gets true.

Let’s move to the next step by adding the Firebase to this Signup Form.

We are not going to add the validation to this form. We have a separate article on Handling Form Validation with Vue.

<script>
import firebase from "firebase";
export default {
    name: "Signup",
    data() {
        return {
            email: "",
            password: "",
            xhrRequest: false,
            errorMessage: "",
            successMessage: ""
        }
    }, 
    methods: {
        signupRequest() {

            let v = this;
            v.xhrRequest = true;
            v.errorMessage = "";
            v.successMessage = "";

            firebase
                .auth()
                .createUserWithEmailAndPassword(v.email, v.password).then(
                () => {
                    v.successMessage = "Register Successfully.";
                    v.xhrRequest = false;
                },
                ( error ) => {
                    let errorResponse = JSON.parse(error.message);
                    v.errorMessage = errorResponse.error.message;
                    v.xhrRequest = false;
                }
            );
        }
    }
}
</script>

First, import the Firebase SDK that provides helpful functions. First, reset the errorMessage and successMessage model with an empty value and apply the true value to the xhrRequest. Because this method only triggers on the form submit event. Now apply the createUserWithEmailAndPassword() function provided by Firebase SDK.

firebase.auth().createUserWithEmailAndPassword(email, password).then(successCallback, errorCallback);

You can learn more about the createUserWithEmailAndPassword() for the Firebase doc.

This is not done yet, because when you try to create your first user, you will get the Configuration_Not_Found error.

Firebase Configuration Not Found

And this because you have to Enable the Email/Password option from the Sign-in providers. Let’s move to the Firebase Console to Enable it. And find the Authentication section like the below screenshot and click on it.

Firebase Authentication Option

Now click the “Get Started” button from the next screen.

Firebase Authentication Get Started

Now, find the Sign-in method tab and click on it. The tab screen appears with multiple Sign-in providers. Find the Email/Password provider and enable it.

Firebase Sign-in provider
Firebase Sign-in Provider

Now, if you try again to register your user then everything works perfectly.

Vue Firebase User Register

So, this is how the Signup process works. Now move to the login template.

Login with Firebase

The method and data model bindings are similar to the Singup template, so we directly jump to the loginRequest method.

<template>
    <div class="row">
        <div class="col-12 text-center mb-4">
            <h1>Log In</h1>
        </div>
        <div class="col-sm-5 m-auto">
            <div v-if="errorMessage !== ''" class="alert alert-danger" role="alert">
                {{ errorMessage }}
            </div>
            <div v-if="successMessage !== ''" class="alert alert-success" role="alert">
                {{ successMessage }}
            </div>
            <form @submit.prevent="loginRequest" id="login-form">
                <div class="row text-left">
                    <div class="col-sm-12 form-group">
                        <label for="email">Email Address</label>
                        <input type="email" v-model="email" id="email" class="form-control form-control-lg">
                    </div>
                    <div class="col-sm-12 form-group">
                        <label for="password">Password</label>
                        <input type="password" v-model="password" id="password" class="form-control form-control-lg">
                    </div>
                    <div class="col-sm-12 text-center form-group">
                        <button v-bind:disabled="xhrRequest" v-bind:class="{disabled: xhrRequest}" class="btn btn-lg btn-primary px-4">
                            <span v-if="! xhrRequest">Login</span>
                            <span v-if="xhrRequest">Please Wait...</span>
                        </button>
                        <div v-if="xhrRequest" class="spinner-border text-secondary loader" role="status">
                            <span class="sr-only">Loading...</span>
                        </div>
                    </div>
                    <div class="col-sm-12 text-center form-group mt-5">
                        <p>Don't have an account? <router-link to="/signup">Sign Up</router-link></p>
                    </div>
                </div>
            </form>
        </div>
    </div>
</template>
<script>
import firebase from "firebase";

export default {
    name: "Login",
    data() {
        return {
            email: "",
            password: "",
            xhrRequest: false,
            errorMessage: "",
            successMessage: ""
        }
    },
    methods: {
        loginRequest() {
            let v = this;

            v.xhrRequest = true;
            v.errorMessage = "";
            v.successMessage = "";

            firebase.auth().signInWithEmailAndPassword(v.email, v.password).then(
                () => {
                    this.$router.replace('dashboard')
                    v.xhrRequest = false;
                }, 
                (error) => {
                    v.errorMessage = error.message;
                    v.xhrRequest = false;
                }
            )
        }
    }
}
</script>
<style scoped>
.loader {
    position:relative;
    top:6px;
    left:10px;
}
</style>

The same step similar to the Signup.vue template, first import the Firebase SDK and use the built-in function.

firebase.auth().signInWithEmailAndPassword(email, password).then(successCallback, errorCallback);

Redirect the successfully logged in user to the dashboard route with this.$router.replace() function.

Now, the final step is to slightly modify the navigation guard from index.js file under the /src/router directory. Replace the authenticatedUser from null to firebase.auth().currentUser.

Make sure to import the Firebase SDK before using the firebase.auth().currentUser.

router.beforeEach((to, from, next) => {
    const authenticatedUser = firebase.auth().currentUser;
    const requiresAuth = to.matched.some(record => record.meta.requiresAuth)
    
    if ( requiresAuth && ! authenticatedUser ) {
        alert("You are not authorized to access this area.");
        next("login");
    }
    else {
        next();
    }
});

We hope this article will help you to learn the Firebase connection and authentication with Vuejs. If you like this article then please follow us on Facebook and Twitter.