In two previous tutorials, How to install Firebase in Vue.JS Project and Using Vuex and Vue-Router in a Vue Project and Using Environment Variables in Vue.js we started to develop a typical Vue PWA SPA App and I discussed some of the important components and features that help simplify building Vue Apps.
In this post will implement Firebase Authentication features in to our project.
With this all set we can now edit our store.js
file to start to make use of the Firebase authentication. If you have following on and continuing to developing on from the code presented in Using Vuex and Vue-Router in a Vue Project and how to split Vuex store into Modules
We are also going to take this opportunity to implement a User Signup Functionality to provide and example of just how easy this is to do so using Firebase.
Import the two Firebase references required then define three new actions :
- Regsiter
- Login
- Logout
The new actions will implement the various methods that are made available via the Firebase API.
Information
The configuration in this article assumes you have configured your Vue App to use Firebase following the instructions How to Install Firebase with Vue.JS
The source code for this Tutorial can be found below. The Relevant Branch will be Authentication.
Register
To implement an Authentication in your web application, invariably you will need a process to enable your users to sign up. In this example, we are going to implement a typical Email and Password combination authentication in Firebase.
In order to make use of this, you will need to configure your Firebase Console of your application and the Authentication section. The Firebase Console Authentication has this particular process really well documented and I would urge you to read through that. However, with that being said it is also a fairly easy process to complete. It is just a matter of choosing which process you want and activating it.

Register page markup
We will add a new view to our application Register.vue
which we will use to enable the user to create an account. Create a new directory in our views
folder which we will call user
, which will contain all the user related views in our application.
mkdir src/views/user
touch src/view/user/Register.vue
I usually make use of MDB Vue Pro Material Design Component Framework to make it easier to Material Design concepts, so if the Mark up looks a little different to what you're used to check out MDB Vue Pro Material Design Component Framework
<template>
<div class="mt-5 p-5">
<mdb-card>
<mdb-card-body>
<form novalidate @submit.prevent="submit">
<p class="h4 text-center mb-4">New User Sign Up</p>
<mdb-list-group v-if="errors.length" class="mb-4">
<mdb-list-group-item v-for="error in errors" :key="error" class="list-group-item-danger">
{{error}}
</mdb-list-group-item>
</mdb-list-group>
<div class="grey-text mt-4">
<mdb-input v-model="email" label="Email" icon="envelope" type="email" required
invalidFeedback="Please provide an email"/>
<mdb-input v-model="password" label="Password" icon="lock" type="password" required
invalidFeedback="Please provide a password"/>
</div>
<div class="text-center">
<mdb-btn type="submit">Sign Up</mdb-btn>
</div>
</form>
</mdb-card-body>
</mdb-card>
</div>
</template>
The JavaScript portion of file we import the required MDB Vue Pro Material Design Component Framework we are going to use. We also import our validation module which we will discuss shortly.
The submit method basically performs some validation and if all conditions pass then will dispatch our values to the Vuex-store to be processed. If the process is successful we will redirect the user to Dashboard page.
If there is an error we will display a login unsuccessful error message.
xxxxxxxxxx
import {
mdbBtn,
mdbCard,
mdbCardBody,
mdbCol,
mdbContainer,
mdbInput,
mdbListGroup,
mdbListGroupItem,
mdbRow,
} from 'mdbvue';
import { Auth } from '../../firebase/auth';
import validate from '../../modules/validation-module';
export default {
name: 'register',
components: {
mdbContainer,
mdbRow,
mdbCol,
mdbCard,
mdbCardBody,
mdbBtn,
mdbInput,
mdbListGroup,
mdbListGroupItem,
},
data() {
return {
email: '',
password: '',
confirmPassword: '',
errors: [],
};
},
methods: {
submit(event) {
this.errors = [];
if (!validate.email(this.email)) {
this.errors.push('Please enter a valid email address');
}
if (!validate.password(this.password)) {
this.errors.push('Your password is not strong enough!');
}
if (this.password !== this.confirmPassword) {
this.errors.push('Password do not match');
}
if (!this.errors.length) {
event.target.classList.add('was-validated');
Auth.createUserWithEmailAndPassword(this.email, this.password)
.then((created) => {
created.user.sendEmailVerification().then(() => {
this.$router.push('/user/profile');
});
}).catch((error) => {
this.errors.push(error.message);
});
}
},
},
};
You'll notice we going to make use of some simple client side validation to ensure that user provides and email address in a valid format.
We also try to enforce some kind of minimum strength on the password. These two functions are provided by a module we are now going to create.
xxxxxxxxxx
mkdir src/modules
touch src/modules/validation-module.js
We going to place our client side validation functions in this module so we have a central repository for reusable validation functions. We are going to make use Regular expressions to validate our strings.
Lets add the following code to our validation-module.js
xxxxxxxxxx
export default {
email: function (email) {
var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(email);
},
password: function(password) {
var re = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,15}$/;
return re.test(password);
}
}
Eloquent JavaScript, 3rd Edition
A Modern Introduction to Programming
Marijn Haverbeke
Reflects the current state of JavaScript
Buy Now Read ReviewLogin in screen
We will create a simple login screen. s
We are also simply going to add a link to the Register page to enable the users who do not have an account to be able to navigate to the register page.
xxxxxxxxxx
<template>
<div class="mt-5 p-5">
<mdb-card>
<mdb-card-body>
<form novalidate @submit.prevent="login">
<p class="h4 text-center mb-4">Sign in</p>
<mdb-list-group v-if="errors.length" class="mb-4">
<mdb-list-group-item v-for="error in errors" :key="error" class="list-group-item-danger">{{error}}</mdb-list-group-item>
</mdb-list-group>
<div class="grey-text mt-5">
<mdb-input v-model="email" label="Email" icon="envelope" type="email" required />
<mdb-input v-model="password" label="Password" icon="lock" type="password" required />
</div>
<div class="text-center">
<mdb-btn type="submit">Login</mdb-btn>
</div>
<router-link to="register">Register</router-link>
</form>
</mdb-card-body>
</mdb-card>
</div>
</template>
We have refactored our login code to follow a similar process to the signup process.
xxxxxxxxxx
import {
mdbBtn, mdbCard, mdbCardBody, mdbContainer, mdbInput, mdbListGroup, mdbListGroupItem,
} from 'mdbvue';
import { Auth } from '@/firebase/auth';
import validate from '@/modules/validation-module';
export default {
name: 'login',
components: {
mdbCard,
mdbCardBody,
mdbBtn,
mdbInput,
mdbListGroup,
mdbListGroupItem,
mdbContainer,
},
data() {
return {
email: '',
password: '',
errors: [],
};
},
methods: {
login(event) {
this.errors = [];
if (!validate.email(this.email)) {
this.errors.push('Please enter a valid email address');
}
if (!this.errors.length) {
event.target.classList.add('was-validated');
Auth.signInWithEmailAndPassword(this.email, this.password)
.then(() => this.$router.push('/dashboard'))
.catch(err => this.errors.push(err.message));
}
},
},
};
Logout
In this example we are simply going to implement the logout functionality in the header of the website. We'll create a re-usable component which will have the typical Login/Logout button.
xxxxxxxxxx
<template>
<mdb-navbar class="navbar-light lighten-5 flexible-navbar"
color="orange"
expand="large"
position="top"
scrolling
>
<mdb-navbar-brand href="https://sourcelink.co.uk" style="padding-left: 150px" target="_blank">
<img alt="SourceLink" class="img-fluid" height="60" src="../../public/img/logo.png"/>
</mdb-navbar-brand>
<mdb-navbar-nav class="nav-flex-icons" right>
<mdb-nav-item :to="{ name: 'login' }" v-if="!user" waves-fixed>Login</mdb-nav-item>
<mdb-nav-item @click="logout" v-else waves-fixed>Logout</mdb-nav-item>
</mdb-navbar-nav>
</mdb-navbar>
</template>
The code itself will be fairly trivial to simply log the user out using the Firebase functionality
xxxxxxxxxx
import {
mdbNavbar, mdbNavbarBrand, mdbNavbarNav, mdbNavItem,
} from 'mdbvue';
import { Auth } from '@/firebase/auth';
export default {
name: 'Header',
components: {
mdbNavbar,
mdbNavbarBrand,
mdbNavbarNav,
mdbNavItem,
},
data() {
return {
user: null,
};
},
created() {
Auth.onAuthStateChanged((user) => {
if (user) {
this.user = user;
} else {
this.user = null;
}
});
},
methods: {
logout() {
Auth.signOut().then(() => {
Auth.onAuthStateChanged(() => {
this.$router.push('/');
});
});
},
},
};
Summary
If you run the application now you will now be able to easily navigate to the Login page and register page and make use of the functionality.
We have improved our little application. However, there are still a couple of issue and we should ideally refactor our application a little because even though it is still a small application both the router.js
and the store.js
file appear to be becoming rather large files with a number of lines of code.
This could become a unmaintainable mess as our application begins to grow. You might want to check out How to implement Navigation Guards Vue
if you enjoyed this article and would like to be notified when the follow up this is published or even would like to know when I publish more tutorials why not subscribe to my newsletter.
Alternatively use the comments below to let me know of any omissions or queries or even just to send me some hate mail!
- What is this Directory.Packages.props file all about? - January 25, 2024
- How to add Tailwind CSS to Blazor website - November 20, 2023
- How to deploy a Blazor site to Netlify - November 17, 2023