Discover more from João Melo
Web App Authentication Workflow with Vue and Firebase
Tutorial on how to develop an essential authentication experience with sign-up, automatic and manual sign-in, and sign-out using Vue and Firebase
The first step users will take in your app is most likely to authenticate themselves. Having been such a familiar feature is interesting to notice how we often overlook the complexity of building auth workflows.
On the one hand, failures are catastrophic. The app could be as good as shut down for someone that can’t sign in to it. Even worse, a malicious actor impersonating someone can wreak havoc on their life and the dev company’s reputation.
On the other hand, people expect much more from apps these days. Some examples include support for third-party providers like Google, Twitter, and Apple; alternative strategies such as emails with magical links or secret codes sent by SMS; and maintenance workflows with password resetting and email verification before the first login. I’m already exhausted 😅.
Aware of those challenges, companies arrived at the market offering cloud solutions that alleviate the burden of building such auth systems and liberate developers to focus on the business features.
On top of the pre-made building blocks, some companies have the advantage of being battle-tested in millions if not billions of daily transactions. They developed powerful tactics to deal with edge cases and attack attempts.
Firebase is one of my favorite solutions. It has an excellent developer experience, supports many features, and has a generous free tier.
This post explores a subset of the authentication surface. It is a tutorial where we create a minimal authentication experience using Firebase. The app will have sign-up, auto and manual sign-in, and sign-out. We will deal with UI flow deciding which interface to show depending on the auth state.
The goal is to understand better how such auth services integrate into web apps.
We are going to build the web app using the Vue framework. Reactive frameworks like Vue simplify the logic to sync the UI with the auth state.
You should be fine if you have initial knowledge of the web stack (HTML, JS, and CSS) or some other web framework like Angular, React, and Svelte.
Nevertheless, please say in the comments If you find that any topic lacks more explanation. I will try to help the best way I can.
Enough with preliminaries.
Our first milestone is to have the skeleton of our Vue application running.
We start by creating a project folder to hold the source code. Inside the new folder, run the following command to initialize an npm package.
npm init -y
Now install Vue.
npm i vue
The browser does not understand Vue files. Vite will compile and serve our code as development goes on. Please install our development dependencies.
npm i -D vite @vitejs/plugin-vue
We instruct Vite to support Vue by creating a vite.config.js file with the content below.
Our web app requires an entry point — time to create an index.html file that initializes Vue and renders a root component. We also need an app.vue file to be the root component. At this point, the root component is just a placeholder. Check the code for both files.
To ensure the plumbing is all set, run Vite with the npx vite command, then check if the app is online at the address provided in the terminal.
Sweet 😎. Now we move to Firebase.
Firebase works with a project concept. The project abstracts a set of backend resources available to one or more related apps. Let’s go to their site and create a project.
Please click on the console button at the top-right corner of the Firebase website. Fill in the required Google credentials. After you log in, click on create a new project and follow the pages the wizard presents — we won’t need the Google Analytics integration. The following illustrates these instructions.
Firebase is a suite of services like databases and web hosting. They need individual activation on a project basis. We go back to the Firebase site to enable the auth service.
Please click the authentication link on the left sidebar of the Firebase project’s page. Choose the get started option and click on the email/password button. Enable email/password on the next page and save.
That was a lot of clicks. Firebase is ready for our web app now. Time to code the integration on the frontend side.
Our app requires a logic layer that receives data and actions performed by the user and communicates with the Firebase authentication service to establish new states like the user is now signed in or signed out.
npm i firebase
Now we create an auth.js file to make a central place to expose the package resources.
We need four functions: one to sign up new users, another for signing in returning users, a third for signing out, and the last to execute instructions when the auth state changes. Don’t bother If any of these functions seems confusing. We will revisit them one by one in the following sections.
The code below initializes a connection to the Firebase project using the configuration we saved in the last section. Then it exposes the auth functions already hooked to this connection. This approach relaxes the rest of our app from worrying about details surrounding Firebase integration.
Let’s think a little about how our app would behave. If the user just arrived, the Firebase library verifies if they are a returning user with a valid session and triggers an auth state change exposing that user profile data. In that case, we should show a welcome page dedicated to automatically signed users.
We could expect the same auth state change behavior when the user manually signs up or signs in with their email and password.
If Firebase can’t establish a valid session upon arrival, it triggers an auth state change. On this occasion, though, the profile data will be null. Then, the user should see a page with controls to input email and password.
This conduct is similar to when the user clicks a sign-out button.
We can develop a centralized mechanism to manage those state changes based on the onChange function imported from auth.js. The root component can appropriately branch which page the user must see after every auth state change, no matter what triggered it.
Please update the app.vue code to establish this logic.
If you are wondering what that ref on line 2 means, Vue tracks variables created with the ref function. Whenever the ref’s value updates, Vue rerenders the template to reflect the new one.
Since the app.vue template will rerender whenever the status changes, the tags with v-if directives will reevaluate considering the latest status, guaranteeing that the app shows correct content.
Something is still missing. We didn’t build PageSign and PageWelcome components. Let’s create a dummy version of those pages within the files page-sign.vue and page-welcome.vue to see some action from the app.
A sign-up form will cheer things up. Don’t you think?
Users create new accounts with an email and password. Let’s open page-sign.vue and layout a form for that.
When the user clicks the sign-up button, the app should capture the form values and pass them to our signUp function imported from auth.js. Two Vue directives can help accomplish this task.
First, the v-model directive syncs data the user typed in an input control with a variable. Second, the v-on (or @) directive triggers a function whenever a given event occurs, like a button click. Using both resources, we build a working sign-up form below.
After creating an account, close the browser tab and reopen it to see Firebase recovering the session. Voilá, we just got auto sign-in for free.
If you are curious, you can go back to the auth project page at the Firebase site. You should encounter the user you just created in the list and see a few admin actions like deleting the account or resetting the user password.
Hi, a small break to say that you can subscribe for free and never miss new posts from the blog.
Show the user private data like blog posts or some calendar appointments would be a possible experience after they authenticate. Firebase creates new users with a unique id attached to them. Any app can take advantage of that and coordinate the storage of the user id beside the corresponding records in a database.
We won’t be covering how to do that in this post. Nevertheless, let’s take the opportunity to improve the welcome page and illustrate how to access that user id.
The app already has access to the user object on the root component. We can take hold of the profile data and pass it to PageWelcome to show it. One way to transmit data between components in Vue is using props. Let’s update app.vue to do just that.
On page-welcome.vue, declare that the component expects a profile object (see line 2 below) and show it on the screen.
Pretty neat, hum?
Enjoying our stay at the PageWelcome component, we could enable the sign-out.
The sign-out workflow is straightforward. We attach our signOut function imported from auth.js to a click event on a new sign-out button.
Although the app will return to the sign page, the only way to reenter is to create a new user. A little lame, agree?
The PageSign component already has most of what is needed to enable a returning user to sign in manually. It lacks (1) a sign-in button beside the sign-up one and (2) a way to trigger the sign function considering if the user wants to sign in or create a new account.
Check the new version of the page-sign.vue addressing those concerns.
Now that our app can sign in users, my question is, do you remember the password you typed to sign up? Huh?
The app won’t give any feedback if the user mistypes the password or try to create an account without an email. It will only stall. Yet, the Firebase auth functions throw errors with insight on what was wrong in these situations. We could improve our PageSign component to show the message returned by Firebase in case of exceptions.
To gain access to errors thrown during execution, we must envelop the sign function call with a try/catch block. Then store the error message in a reactive variable. That way, Vue can automatically update the screen.
That’s it. The complete source code is available here.
We covered a lot today.
Considering the gap between what we have now and what a production-ready authentication workflow should be, the missing scope illuminates learning opportunities.
The most obvious one is the user experience. Buttons, inputs, and pages lack branding, and there isn’t feedback for loading states, for example. A UI library like Bootstrap or Bulma can facilitate this upgrade.
Regarding auth capabilities, we just scratched the Firebase features. Their documentation has excellent guides on integrating with third-party providers or implementing must-haves like email verification and password reset.
Do you think any of those topics would be exciting for a new post? Let me know in the comments.
See you 👋.
If you think this post can help someone, please share it with them. Better yet, subscribe for free and receive fresh content in your inbox whenever it is published on the blog. I will never send more than one email a week.