Using Firebase Authentication in a Nuxt Server-side Rendered Application

Austin Davies
Level Up Coding
Published in
6 min readFeb 3, 2020

--

Nuxt JS logo next to Firebase Logo

Using Firebase authentication with a universal application can be, well, not exactly straight-forward. My aim for this article is to share my experience of making Firebase client-side authentication play well with the Nuxt.JS framework in a predictable way and without sacrificing any of the built-in functionality of the Nuxt.JS framework.

Preface

There are a plethora of questions littered across Medium, Stack Overflow and a few other sites as well, not to mention the countless articles you may uncover as well. Sadly, they fail to give answers that work, can mislead, reiterate others past answers, are dated, or just aren’t applicable to universal mode Nuxt.JS applications.

You might be tempted next to see what libraries exist on the market. At the time of this writing, there really isn’t much out there in terms of plug-n-play modules/libraries for getting Nuxt to work with Firebase authentication. And of those libraries that exist, none seem to provide a solution that works in universal mode. However, a library named nuxt-fire by Lupas — whom is the author of the library — does look promising if it continues to progress; I say “promising if it continues to progress” because, as it serves to be the best plug-n-play Nuxt.JS module out there currently, it isn’t that great in terms of providing a solid solution for using authentication with universal mode.

Time for Nuxt-Fire to Somewhat Rescue Us

Lupas’s module is good for getting Firebase’s many services integrated into Nuxt while also providing a few of his own experimental features for some of those integrations — we will be using this library in our app. Moreover, Lupas seems very passionate about his library and getting it to be the best and most well-rounded solution out there. At its current version (3.5.5) you can simply enable auth by passing a boolean into the module options or an object containing names of Vuex store mutations and actions that will be called when certain Firebase auth events happen, along with an option to set SSR.

Now when I saw the option for SSR in the documentation for configuring the auth integration, my eyes lit up. I thought “Hallelujah! Someone finally did it!” and after reading over what that option did and the code that gets enabled as a result as well as the Firebase documentation, I started to get second thoughts.

Premise of Lupas’s Authentication Solution

Lupas’s solution comes packaged with a service worker, a piece of Nuxt.JS server middleware, and a plugin. The service worker works off the fetch event to ensure anytime the browser needs to fetch anything it will hijack the request and set the authorization header for specific requests with the current users id token. The server middleware looks for the previously set authorization header and will set a couple of properties on the response object containing information about the user from the decoded claims. And finally, the plugin sets up the onAuthStateChanged event listener that will commit and dispatch the aforementioned Vuex mutations and actions accordingly.

The core issue I experienced with Lupas’s solution are the assumptions it made. First off, it wants me to register a service worker which seemingly is copied internally from the nuxt-fire library, to your apps static directory on each Nuxt build. Secondly, I don’t know if this is specific to Firebase Functions or hosting solutions in general, but I’ve noticed if I am not running a server framework (e.g., express, fastify) then any registered Nuxt server middleware will not execute in production if hosted on Firebase Functions. However, this is not immediately apparent as server middleware will execute when running a dev server.

Defining the Solution

Heads-up! We will be using nuxt-fire, Axios, a custom Nuxt plugin, and the nuxtServerInit call in the coming-up solution. But before we get started, I will briefly go over the high-level concept.

nuxtServerInit

The nuxtServerInit will check for the existence of a cookie that we will set client-side and that contains the currently logged-in user’s ID token. If this cookie exists, we will attempt to verify the ID token with Firebase Admin. If the ID token is valid we will decode the ID token and commit the claims contained in token to our Vuex store for use with our auth-listener plugin.

The Auth-Listener Plugin

The auth-listener plugin is a plugin that will only run client-side and is responsible for checking the Vuex store to see if the user was able to be authenticated from the server and is also responsible for registering the onIdTokenChanged event listener offered to us from Firebase. Take note here because the order of what goes on here is important. The Vuex auth check in this plugin is needs to come first because we need the ability to call $fireAuth.signOut() before registering the onIdTokenChanged event listener otherwise the user session will get refreshed. This is important, if the server did not initialize our Vuex store with user information it means that the ID token was not valid. Then come time for our client-side plugin to run, we want to make sure it doesn’t think that the user is authenticated, which can cause a client/server render mismatch.

The Axios Interceptor

Finally, if you are making API requests that require authentication and is expecting your ID token as that means of authenticating a user, then you will need to use a request interceptor. Don’t worry if you don’t fit this requirement. Just skip this section. Thankfully Axios makes intercepting requests easy. Let’s outline the reason for needing an interceptor. We need to ensure, before sending a network request, we have the most up-to-date ID token before making a request to our API. This will mitigate any chance of the server sending us back an unauthorized request. Imagine this, you have 1 second before a given ID token expires. Let’s say you make a request on a slow connection, thus the request doesn’t hit the server until 2 seconds after the client sent the request. See the issue? The client thought we were authenticated, but the server, due to time latency, saw the opposite. This is why it is important to update the token before sending it off.

Time to Get to Work

Let’s start by installing the 6 necessary NPM modules:

With those installed, let’s define the Vuex store actions, getters, and mutations needed:

Note: The cookie name is important here, especially if you use Firebase Functions; it has to be __session.

Next, we’ll need the auth-listener plugin:

The _handleAuthError function in the preceding code is there for you to implement; it’s not pertinent to this example.

Next, we’ll need that Axios interceptor:

I will admit, I thought what Lupas did to force the Firebase auth to become available on-demand was pretty cool. So the principal idea is you await a promise that executes Firebase’s onAuthStateChanged event listener, capturing the unsubscribe as a result. You then unsubscribe the event listener immediately and then once auth is available, you get the user and can resolve the promise. So give that man props for thinking-up that piece of code.

Finally, just for completeness, I will provide the pertinent parts of the nuxt.config.js:

You will need to follow Lupas’s Configuration guide for nuxt-fire: https://nuxtfire.netlify.com/guide/getting-started/#simple-configuration

Conclusion

There you have it! I hope you found this helpful and if I missed something please let me know (this was a long article) XD. Also, you can extend this example. Let’s say you want the server to redirect you to a page that renews the session when the existing one has expired, then that page redirects you back to the original destination. Anyway, Good luck and until next time.

--

--