Firebase offers great service for authenticating users in your app. It’s for those of you who -like me- don’t want to spend long hours, first choosing and learning backend framework and then implementing authentication.
There’s a great article about firebase auth in Vue apps. If this is your first encounter with VueJS+Firebase you should definitely check it out. Anas Mammeri does a great job explaining from scratch how to get started.
The approach was easy and straightforward but when you’re build an app you’ll probably face same problems as I did.
While playing around I struggled with following concerns:
- how to update components that depend on user auth state when it changes
I really wanted to take full advantage of firebase reactivity and respond to changes on user model rather than just check the model when I needed to. Suppose we have navigation menu that depends on user state. If user is authenticated, we show avatar and logout button, otherwise just show sign-in/sign-up links. We also want the component to update anytime user state changes (e. g. sign in, logout )
- separate Firebase Auth logic from the app
I really don’t feel comfortable referencing firebase lib (or any other for that matter) directly in the components (or actions) and they should now about the auth as little as possible.
- require login before entering particular route, and continue to it after user signs
Theres nothing more frustrating when entering a specific page than first having to sign in and then being redirected to main page again.
All the code can be found here
- Move any firebase logic into custom Vue plugin
We’ll have all our Firebase code wrapped around a plugin and the app will interact with the service only through plugin methods.
- Store user object in Vuex
We will keep our user stored in Vuex store so we can take advantage of all goodies that come with Vue+Vuex(
computed properties etc.) and keep data flow in our app as simple and robust as possible.
- pass in params next route and redirect after login
In order to continue to previous route after sign in, we’ll save our route in query params and pass them tho sign in component (e. g.
/signin?redirect=%2Fprofile ). Then, after login the app will replace
/signin route with target route (e. g.
First let’s setup our store to handle user accounts.
If your not new to Vuex there’s nothing new here:
- setup initial user object to be
null(not logged int)
- add mutation for handling user updates
- add getter for observing user
Now, when we have our store ready, let’s create a plugin wrapper for firebase auth service
- set up a new plugin
FirebaseAuthPlugin(see here for details)
configcontains standard Firebase credentials (you can get them here), please remember to set up authentication
- import current app
$authobject will contain all auth operations (login, logout, registration)
authstate changes in
onAuthStateChangedand dispatch any changes to our
- note that
asyncbecause we also want to know if the request completed
Update: handling auth session
Following Daniel da Rocha question — all auth session management is handled by firebase-auth plugin, so all you need to do is to ensure that your
user model in the store is synced with model returned in
Continue back to route after user signs in
Now, lets setup our
Our router has pretty much standard configuration. Thing to note is
meta field in
/profile route. This will indicate that particular route is restricted only for logged in users.
Note that we import our
store in order to have access to
The whole magic happens in
beforeEach method. If you already did some Vue development it’s probably nothing new otherwise read about vue-router. First we check if next (
to ) has
authReqired flag. If yes, then check wether the user is signed in. If no, we redirect to
/signin and add our target route as
So now that we have our auth bound with Vuex
store we have a normal data flow so in our
Navigation component we can look like this:
Note that as bonus we get a bit less complicated test cases as we don’t worry about mocking Firebase, instead just mock our Vuex store with data needed in the component and make assertions.
Update : Keeping user sign in after page reload
Another good question from Daniel da Rocha — will the user have to re-authenticate after closing the browser or reloading the page?
We should consider two scenarios here.
- User enters a route which does not require authenticated user.
In this case we don’t have to worry about re-authenticating the user as firebase will consist our session. After reloading the page
onAuthStateChange will be re-attached and if the session will return
user then we’ll just commit it to our store and trigger any updates in our components.
2. User enters a route which does require authenticated user.
This is more complex because our router usually gets called before
onAuthStateChange is triggered, so we probably won’t have
user in our store.
This can be easily fixed by attaching watcher in our sign in component:
This ensures that anytime user model changes and is a valid user we will be redirected to our destination route.
Unfortunately in most cases, for a brief second users will see sign in screen — that’s a bit awkward from UX point of view. But we can go a step further and ensure the
user is cached. To do this we could use Vuex plugins to store our
localStorage . Please read documentation for more info.
By moving Firebase boilerplate into Vue plugin we now have all the auth related logic in one place. We also made our user data reactive so no anytime our user model changes, the app and components are also updated. Also unit testing should be a bit simpler since we don’t have to stub Firebase service in order to render component.
Check out the code here