Discover more from João Melo
Web App Authentication with Email Magical Links, SMS Security Codes, and Google Accounts Using FirebaseUI and Svelte
In a past post, I wrote about creating an essential web authentication workflow with Firebase and Vue. A reader suggested exploring an additional resource provided by Firebase called FirebaseUI. This post follows that suggestion.
FirebaseUI is an open-source UI library that sits on top of the Firebase SDK. It implements visual controls, navigation, and integration logic for web app authentication.
The main advantage of using it is to reduce coding effort and the number of bugs that always accompany new code.
Today we will use FirebaseUI to enable users to sign with the traditional email and password, but also with email magical links, SMS security codes, and Google accounts.
Besides the Firebase SDK and the FirebaseUI libraries, we will build the web app using the Svelte framework. Reactive frameworks like Svelte simplify the instructions to sync UI with the application state.
You should be fine if you are familiar with the web stack (HTML, JS, and CSS) or some other web framework like Vue, Angular, and React.
In the last section, I mentioned a previous post that took the time to create a minimal auth experience using Firebase and Vue but without relying on FirebaseUI. You don’t have to read that post to understand this one. Even so, starting there could be more helpful if you are unfamiliar with Firebase Authentication.
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.
Up and Running
Our first milestone is to have the skeleton of our web 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
The browser does not understand Svelte files. Vite will compile and serve our code as development goes on. Please install our development dependencies.
npm i -D vite svelte @sveltejs/vite-plugin-svelte
We instruct Vite to support Svelte with a
Our web app requires an entry point. Time to create the
index.html file with boilerplate markup to replace later.
Next, to ensure the plumbing is all set, run Vite with the
npx vite command and check if the app is online at the address provided on the terminal.
Svelte (like other component-based frameworks) abstracts the UI in a component tree, starting with a root component representing the whole app.
We create the
app.svelte file to source a root component. For now, we leave it with a placeholder message. Then we update the
index.html file to bring the root component from
app.svelte and render it a target
Sweet 😎. Now we move to Firebase.
Now we go to the Firebase console to create new a project, activate a web app inside the project, and bring the configuration data into a new
firebase.config.js file in our source code.
With that covered, please go back to the Firebase site and click on the authentication service link. Choose the get started option and click on the email/password button. Enable email/password and email link on the next page and save. Also, enable phone and google providers with their default configuration.
Firebase is ready for our web app now. Let’s 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.
We use two firebase packages to do the heavy work for us. The first is the firebase SDK which encapsulates the communication between our web app and Firebase services. Secondly, the firebaseui package will render the visual controls regarding the sign-in while driving the SDK.
So open a new terminal window (without closing the one where the Vite process is running) and install both libraries.
npm i firebase firebaseui
Our web app components will need three functions to take advantage of those libraries’ resources. The first function starts and passes the control to FirebaseUI, another for signing out (which is not covered by FirebaseUI), and the last to execute callbacks whenever the auth state changes.
Please create an
firebase.auth.js file to make it a central place to expose those functions mentioned before. There, we initialize the Firebase connection and, for now, leave the functions with boilerplate code that we will replace as needed in the following sections.
Let’s consider how our app should behave regarding its two primary states. On the one hand, if the user is signed in, we must show a welcome page with business data and an option to sign out. On the other hand, if they are signed out, they should see a sign page with the controls provided by FirebaseUI.
We can subscribe to a Firebase trigger that fires every time this auth state changes, no matter the mechanism. The trigger will invoke a callback we provided upon subscription, passing the user profile data (if signed in) or
null (in case of sign-out).
With that, we can develop a centralized solution at the root component to decide which of the two app pages appears.
To support that central switch, we will need to expose the capacity of the
onChange function at the
firebase.auth.js file. It must support the invocation of arbitrary callbacks whenever Firebase detects a state change.
Last, we build a dummy version of the
PageWelcome components. With that covered, we can see a glimpse of our app.
At the root component, Svelte takes care to rerender the template when the
status value updates. This reactive pattern put together with the
else blocks guarantees that the app shows correct content based on auth state.
Time to put FirebaseUI to work.
Since the root component will render
PageSign when the user is signed out, that will be the place to ask FirebaseUI to control the app flow.
First, we should update the
startUI function exported from the
firebase.auth.js file to do just that. It envelops the FirebaseUI
start function and exposes the feature in a pre-configured form.
start function from the FirebaseUI library takes two arguments. The first is the element id which will contain the library’s pre-made user interface, and the second is a configuration object with a flexible list of options.
As FirebaseUI configuration options go, we need to inform the target providers: email, phone, and google. We also set the
signInSuccessWithAuthResult callback to do nothing and return
false. Our web app needs this awkward callback behavior so FirebaseUI does not redirect (forcing a refresh) after completing the sign-in process.
Next, we return to the
page-sign.svelte file and create an empty
div containing the FirebaseUI magic. We use the Svelte
onMount hook to execute the
startUI function. The hook runs instructions once at the beginning of a component lifecycle.
The number of features we gain when putting these libraries together is impressive. I can only imagine the wonders you folks will build on top of that.
Hi, a small break to say that you can subscribe for free and never miss new posts from the blog.
Now that users can sign in, we could improve our welcome page to show some data about the user and enable sign-out.
First, since the root component already passes down the user email and id values, we need to declare them as properties in the
PageWelcome component so we can refer to them in the template.
Next, we update the
signOut function in the
firebase.auth.js file. Then import it inside the
PageWelcome component. With that settled, tie the function to the click event of a button in the PageWelcome template.
Our tutorial is good as done. You can refer to the complete source code here.
I’m always mesmerized by how fast we deliver professional-looking experiences using component libraries like FirebaseUI. It also makes me remember my first days developing for the web and how Bootstrap helped me alleviate the backlog of new things to learn.
You see, the web is made of so many moving parts. It’s easy to get overwhelmed by a gigantic learning roadmap, and new things are constantly popping up. In my opinion, this role as a stepstone in the learning path to senior skills is the main advantage of using such component libraries.
I don’t embrace their speed in development so much for projects with a long-term perspective. After some years in the industry, I came to the opinion that the trade-offs in rigidity eclipse the legitimate gains in dev speed. That does not include short-term apps like those made for hackathons or prototypes.
In my experience, always comes the moment when we must implement something the library can’t offer. Then you need to reproduce its look and feel in a new component. Perhaps its version starts to conflict with crucial elements like the underlying framework. You will now need to replace or freeze the version of one of them. Those problems are hard to solve and hinder app sustainability.
Nevertheless, take my opinions with a grain of salt. These open-source projects have helped millions in our community (including me) for free over the years. Their maintainers deserve a lot of respect.
The personal lesson I want to share is this: be aware of the trade-offs involved when deciding to use a UI library versus building your components.
I would love to learn what you think about the subject and the post in general. Please share your thoughts in the comments.
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.