Ngxs and Firebase Authentication
How to store the Firebase auth state in Ngxs
I am working on a very small Angular application. I did not want to make a custom solution for authentication so I decided to use an existing one. It is also important that only my colleagues from Exponea can sign in to the application. Perfect excuse to give Firebase a shot!
Adding Ngxs State
I started by adding Ngxs to my application.
yarn add @ngxs/{store,router-plugin,devtools-plugin}
This command installs the base package, as well as adding support for Redux dev tools and the router. Then I added the required modules to my main module.
User State
I want to store my authentication state in a user state. So I created a new file called user.state.ts
and added a new class for the state. In Ngxs, you create Typescript classes and use decorators to define the state and its actions. Cool, eh?
The file contains the definition of the data model of the state as well as the actions it reacts to. The UserStateModel
interface contains a User
(or null if not signed in) and loaded
boolean which indicated whether the user was already loaded.
The UserState
class defines the state itself. You can see that it is decorated with the@State
decorator. The state will react to 3 actions — logging in, logging out, and setting the user (this one will be used to set the loaded user from Firebase later).
When the user presses a login button, the LoginAction
is dispatched to the store. Similarly, when the user visits the /logout
page, the LogoutAction
is dispatched to the store. Ngxs allows you to wait for the action to complete so it allows me to do this in the page view component:
I can wait for the logout action to complete and then redirect to the login page. Easy.
Adding Firebase
In order to implement the authentication, it was time to add Firebase to the application.
yarn add firebase @angular/fire
Just like before, I started by adding the Firebase module to my main module.
You probably noticed that there is a reference to environment.firebaseConfig
. This is in the environment.ts
file and it is different for development and for production. I had to create 2 Firebase projects in the Firebase console and copied each configuration to the environment files.
Logging In and Out
Now I came back to the user state which I created earlier. I could now implement the login and logout actions using Firebase.
There are a few important points in this implementation. First, I injected the AngularFireAuth
service to interact with Firebase. Then I created an authentication provider — in this case, I wanted to use Google authentication — and set a custom parameter hd
to our Exponea domain. This tells Google to only allow people who have an Exponea email to log in. It also shows it in the UI. Finally, in the action handler functions, I used signInWithRedirect
and signOut
. You can also use signInWithPopup
instead if you want. Note that there is no extra step required to make the redirect work, Firebase takes care of that for you.
Also, note that both functions are async
and I used await
in the function bodies. Ngxs actions can be asynchronous and that allows you to wait for them to complete.
To finish off, I needed to get the user from Firebase and place it in the Ngxs store to use it further in my application. Thankfully, this is very easy because Firebase exposes an observable of the user.
As you can see, all I did was to subscribe to the observable provided by Firebase and dispatch Ngxs action to update the state. There’s one catch — you cannot store the whole user in the Ngxs state because the provided object contains also a few methods and internal properties. So instead I made a private function to extract the important user properties and only store those in the Ngxs state.
That’s it!
Thank you for reading this article! If you like it, well, you know what to do. 👏👏👏 + ❤️❤️❤️ + Follow me for more great content. Have a wonderful day!