User Authentication with Firebase - ECE-180D-WS-2024/Wiki-Knowledge-Base GitHub Wiki

Firebase Setup and User Authentication

Introduction

Say goodbye to the tedious tasks of software development because Firebase [1]has revolutionized web development! From seamless database integration to effortless user authentication, Firebase automates the grunt work, allowing anyone to deploy their first web application regardless of experience. Standing out as a free and versatile app development platform, Firebase offers a suite of user-friendly tools to deploy robust and scalable applications. With features like real-time databases, user authentication, and web hosting, Firebase serves as a comprehensive Backend-as-a-Service (BaaS)[2]. What's more, Firebase's extensive Software Development Kits (SDKs) and broad cross-platform support makes Firebase the ideal choice for developers to write full-stack applications with minimal backend code. Furthermore, Firebase is backed by Google, so you can focus on development without concerns of security or reliability.

In this tutorial, we will delve into the basics of hosting a web application with user authentication. Using basic Javascript and HTML, we will create a fully functional site with a login page. From there, the possibilities are endless. Whether you wish to host a multiplayer game, communicate with hardware, or store real-time data, Firebase provides streamlines the development to bring your idea to life.

Why Firebase?

Firebase is most recognized for its unique cloud-hosted real-time database. Unlike traditional databases that require the user to refresh to pull new data, Firebase automatically synchronizes all clients with the latest data—an absolutely essential element of any low-latency real-time collaborative application.

Furthermore, Firebase utilizes an event-driven architecture with asynchronous requests that eliminates the need for regular polling to communicate with the server. In fact, this underlying architecture was designed to be highly scalable for a large number of concurrent users, all while remaining performant. By leveraging the local cache, Firebase even provides robust offline support that allows applications to function seamlessly despite an abrupt loss of connection [3].

But the benefits don't end there. Since Firebase stores all of your data as a json file, communicating with the server is as easy as sending an HTTPS request [4], and it's fully secure. Thanks to this easy-to-use and streamlined process, developers can forego the complexities of maintaining a backend infrastructure, and instead focus on the front-end or application itself. And of course, for your average project, Firebase is completely free.

Getting Started

This tutorial leverages Firebase's user-friendly setup and detailed documentation [5] to host a simple website that supports email and password user authentication. This guide assumes familiarity with Javascript and html, but should be easy to follow nonetheless.

Setup

We begin by creating a new Firebase project:

  1. Navigate to https://console.firebase.google.com/ and click "Create a Project"
  2. Choose a name for your project and accept the necessary conditions.
  3. Click Settings -> Project settings -> General -> click the web app symbol under Your apps.
  4. Choose an App nickname -> check the box to set up Firebase Hosting and register your app.
  5. Click Use a <script> tag and copy the scripts and save it for later.
  6. Click Project Overview -> Authentication -> Get started -> enable Email/Password and click save.

Now, install Node package manager (npm) from https://nodejs.org/en/download/current. Once npm is installed, we proceed with the installation of Firebase.

Install Firebase using npm:

npm install -g firebase-tools

Run the following command and sign in with the same Google account you used to create the Firebase project.

firebase login

Navigate to your desired project directory and run the following command. Select yes when asked to proceed followed by "Use an existing project," and choose the Firebase project we created. Choose the desired public directory, or leave it as (public). Select yes to configure as a single page-app, and do not set up automatic builds and deploys with Github.

firebase init hosting

Now when we run the following command and visit the url http://localhost:5002, we should see the default Firebase site.

firebase serve

Image 1

Now, any time during our coding process, we can refresh the url to see our changes. The command firebase serve hosts our webpage locally so that we can guarantee its functionality before the final deployment.

We're finally ready to begin the web development. For the sake of this tutorial, we will create a bare bones login page using HTML. Open the index.html file from the public directory and replace the default Firebase HTML file with a basic HTML template. We need to create a basic container for our login and register buttons. In case you are unfamiliar with HTML, we have provided a starter index.html file here to help you get started. To stylize your web app, you can make a CSS stylesheet, but that's outside the scope of this tutorial. At this point, our site should look like this:

Image 1

Next, to connect our web app to Firebase, we edit the index.html file and paste the script tag from earlier into the bottom of the <body> tag. Make sure the script tag is above the index.js script tag so that all components load before the Javascript file. Now we just need to import the authentication and database functions from Firebase. Within the script tag we just pasted, copy and paste the import initializeApp line, and replace initializeApp with getAuth and also replace firebase-app.js with firebase-auth.js in the url. Repeat the previous step once more to import getDatabase from firebase-database.js. At this point, we should have the following imported functions inside the script tag:

// Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.9.0/firebase-app.js";
import { getAuth } from "https://www.gstatic.com/firebasejs/10.9.0/firebase-auth.js";
import { getDatabase } from "https://www.gstatic.com/firebasejs/10.9.0/firebase-database.js";

...

// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const database = getDatabase(app);

Now we create a file index.js in the same directory as index.html. The index.js file will contain the event handlers for the login and register buttons. When either button is clicked, we should validate the email and correctly authenticate it as a new or existing user. In order to validate an input as a proper email, we can write a function to match the user input with the regex /^[^@]+@\w+(\.\w+)+\w$/ and return a bool as shown here. It is important to note that we aren't concerned with whether or not the email actually exists.

We should also create a register function that takes the user inputs and validates the email using the function we just created. Now that we have the email and password stored as variables, we can use Firebase's built in auth.createUserWithEmailAndPassword function to authenticate the user. Then we can create a dictionary to store the user data and push it to Firebase using another library function database.ref().child().set() as shown here.

Similarly, we can create the Login Function to handle the event where the login button is pressed. Once again, we begin by validating the email. If the email is determined to be valid, we use the library function auth.signInWithEmailAndPassword since the user already exists in the database. The fully implemented function is documented here.

With all our functions in place, now we need to define the rules of our database. In the Firebase project, click Realtime Database -> Rules and paste the following:

{
  "rules": {
    "users": {
      "$uid": {
        ".read": "$uid === auth.uid",
        ".write": "$uid === auth.uid"
      }
    }
  }
}

This ensures that users can read and write to their own user data, but no one else's. Now that our authentication is working, we are ready to deploy the webpage!

firebase deploy

We observe that our connection to the webpage is completely secure, without any additional code!

Firebase Alternatives

Google Firebase provides an easy-to-use, well-documented software development kit that is simple to set up for user authentication tasks. It integrates with many other Firebase services like Firebase analytics, Firebase real-time database, and Google Cloud functions. However, it may fall short in its fixed user authentication workflows when compared to alternative user authentication services. Firebase is not well suited for applications that require highly customized authentication mechanisms and refined user data control. Since Firebase is built through Google infrastructure, it can also be difficult to migrate your application from the Google environment to a different platform. Here are some Firebase alternatives to consider when building an application that requires user authentication.

  1. Auth0 supports login through popular socials (e.g. Facebook, Github) and is comparable to Firebase in its scalability and user data security. However, it is much more flexible than Firebase as it allows for custom authentication workflows and detailed control over user data. Some of these user management features include role-based access control and user activity logging. This additional flexibility comes with a steeper learning curve.
  2. Amazon Cognito Integrates with AWS services such as Lambda, API Gateway, and Dynamo DB. It also provides fine control over user management, but not at the same level as Auth0. However, Amazon Cognito can have a steep learning curve as leveraging its full potential requires familiarity with the broader AWS ecosystem.
  3. Okta is an enterprise-focused user authentication system that is best suited for use in large organizations and existing enterprise user management systems. It has advanced features like single sign-on (SSO) and user data lifecycle management, which caters to the needs of larger enterprises. It is also designed to handle extremely large-scale user bases, but using Okta can be extremely expensive as it is really only designed for corporate use.
  4. Keycloak is a free, open-source user authentication service that is highly customizable. It provides SSO support and allows for custom user attributes similar to Auth0. Keycloak can also be self-hosted, which allows for full control over the authentication infrastructure and security features. However, this management and maintenance of the authentication infrastructure can be complex and resource-intensive.
  5. Microsoft Azure Active Directory B2C Integrates with the Microsoft ecosystem, which includes applications like Office 65 and Azure functions. Azure AD B2C also provides customizable authentication flows and is designed to scale well for extremely large products. Similar to Amazon Cognito, it has a significant learning curve in learning how to leverage all the functionalities available in the Azure ecosystem.

Altogether, Firebase is a great choice for implementing your first user authentication system and understanding how user data is stored and updated. But when developing a full-fledged application, it is important to consider whether the application will integrate with a particular ecosystem (e.g. Google, AWS, or Microsoft Azure) or require a certain level of control over the user authentication workflow. Different authentication services will also have a cost and learning curve associated with the additional functionalities they provide.

Conclusion

Congratulations! You have successfully deployed your first web application with user authentication using Firebase. As you probably experienced, Firebase greatly reduces the amount of backend development with its powerful library functions. In fact, with only basic knowledge of HTML and Javascript, we can tackle the challenge of deploying a full-stack web application!

Moreover, any real-time multiplayer activity requires constant updates of data and synchronization between all clients. Firebase is an excellent choice for a secure, real-time, and highly performant database and backend to meet those needs. With only a few lines of code, you can deploy a fully functional web app with user authentication and store any data for free, which makes Firebase the ideal backend provider for most projects.

Code Reference

Starter HTML page

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Firebase Login</title>
    <link rel="stylesheet" href="index.css">
  </head>
  <body>
    <div id="wrapper">
      <div id="header_container">
        <h2 id="header"> Firebase Login </h2>
      </div>
      <div id="login_container">
        <input type="email" id="email" placeholder="Email">
        <input type="password" id="password" placeholder="Password">
        <div id="button_container">
            <button onclick="login()">Login</button>
            <button onclick="register()">Register</button>
        </div>
      </div>
    </div>
    <script src="index.js" type="text/javascript"></script>
  </body>
</html>

Validate email

// Validate Email
function validate_email(email) {
    expression = /^[^@]+@\w+(\.\w+)+\w$/
    if (expression.test(email) == true) {
      // Email is good
      return true
    } else {
      // Email is not good
      return false
    }
}

Register function

// Register Function
function register () {
    email = document.getElementById('email').value
    password = document.getElementById('password').value
    // Validate Email
    if (validate_email(email) == false) {
        alert('Invalid Email')
        return
    }
}
// User Authentication
auth.createUserWithEmailAndPassword(email, password).then(function() {
  var user = auth.currentUser
  // Add User to Database
  var database_ref = database.ref()

  // Create User data
  var user_data = {
    email : email,
    last_login : Date.now()
  }
  // Push to Firebase Database
  database_ref.child('users/' + user.uid).set(user_data)
  alert('User Registered')
}).catch(function(error) {
  var error_message = error.message
  alert(error.message)
})

Login function

// Login Function
function login () {
    // Get all our input fields
    email = document.getElementById('email').value
    password = document.getElementById('password').value
  
    // Validate Email
    if (validate_email(email) == false) {
        alert('Invalid Email')
        return
    }
}
auth.signInWithEmailAndPassword(email, password).then(function() {
  var user = auth.currentUser
  // Add User to Database
  var database_ref = database.ref()

  // Create User data
  var user_data = {
    last_login : Date.now()
  }
  // Push to Firebase Database
  database_ref.child('users/' + user.uid).update(user_data)
  // DOne
  alert('User Logged In!!')
}).catch(function(error) {
  alert(error.message)
})

Sources

[1] https://firebase.google.com/

[2] https://www.youtube.com/watch?v=vAoB4VbhRzM

[3] https://firebase.google.com/docs/database#:~:text=The%20Firebase%20Realtime%20Database%20lets,end%20user%20a%20responsive%20experience.

[4] https://firebase.google.com/docs/functions/http-events?gen=2nd

[5] https://firebase.google.com/doc

https://console.firebase.google.com/

https://nodejs.org/en/download/current

https://firebase.google.com/docs/web/setup#add-sdk-and-initialize

⚠️ **GitHub.com Fallback** ⚠️