A Modular Approach To Authentication in Nuxt (Implementation)

Ifeanyi Ibekie
9 min readAug 27, 2020

If this is your first article in my modular authentication in nuxt series, I recommend taking a look at the link below before you proceed to understand what is being done in this section.

TLDR https://github.com/dop3ch3f/nuxt-auth-tutorial

INITIAL SETUP

Its time to get our hands dirty on implementing the authentication solution for nuxt. First things first, we start with a brand new SSR Nuxt project. You can follow the guide at https://nuxtjs.org/guides/get-started/installation). This would be the default scaffolding and the starting point of this tutorial. I strongly recommend using create-nuxt-app as it provides a step by step approach of asking you the features to enable and disable plus doing a lot of the heavy lifting in setting up the integrations.

After the initial setup of the default scaffolding head over to your package.json to add some of the packages from the image below.

These are the npm packages. try as much as not to update the versions as they may break your application

Ideally, everything from vuex-persist to js-cookie should be added to your package.json dependencies field. Then run “npm i” to install them. The next step is to configure our vuex store.

SETTING UP VUEX

The vuex store is going to serve as the id card of each user. Holding the information our navigation guards would need to handle the user's requests appropriately, vuex is available in Nuxt by default but disabled so we would enable it by creating an index.js file in our store folder.

store/index.js

We exported the state and mutations as empty because we would be using the store modules approach (PS. I strongly recommend this approach for large scale applications). Up next is to set up the auth module of our store as this would be responsible for holding the auth data of any user in our application.

store/auth.js

To keep the tutorial short and down to the point, we are only holding the user field which we would use in our navigation guards to handle every request and of course we have to include methods to read and update the state fields. Our store setup is not yet complete as we need to set up store plugins that would sync our vuex store as cookies to be able to use both on the browser and server runtimes of Nuxt.

SETTING UP VUEX PLUGINS

After setting up our vuex store and structure we need to add the necessary plugins to make it available as a cookie and to be synced across the browser and server runtimes of Nuxt.

plugins/vuex-persist.js

We create the plugin file for our persisted state, we follow the recommended format in the documentation at https://www.npmjs.com/package/vuex-persistedstate but with a little twist. The twist is we use ‘js-cookie’ to handle browser-cookies and we use ‘cookie’ to handle for server-runtime cookies this is because we expect manipulations to the state in the middleware (Server Runtime) to be committed on the server before sent to the Browser Runtime and Vice versa. So the process.client is used to differentiate between the server and client runtimes of Nuxt and would run the libraries used for handling cookies respectively. The rest is self-explanatory, do not forget to register the plugin in your nuxt.config.js file. Here's a little assignment, try encrypting and decrypting your state using the set and get item methods of this module so that hackers don’t sniff up your applications state from your application cookies. Up next is setting up the utility methods that would help us in configuring our route guards.

UTILITY METHODS

services/utility.js

Here we include the utility methods we would use in our auth middleware. The file is necessary so we can keep our code dry and also reuse code. The utility methods are namely :

  1. isSameURL: This utility method checks the two inputs (which are supposed to be string URLs) to know if they are the same. This method is necessary as in our middleware especially on the browser runtime anytime an unauthorized request comes in we redirect the user to the login route. Now if we don't use this method to stop the redirection when the route is a login route. we would end up with a redirect loop. So the idea is we use this method to check if to routes are the same. If it is still very unclear to you, sit tight, when we get to the implementation of the middleware it would be clear.
  2. normalizePath: As the name says, this method is used to strip a route path of its query parameters so that if a person is authorized to hit ‘/home’ it would allow for hits of the ‘/home’ and ‘/home?foo=bar’. This is necessary as not normalizing your paths would redirect users hitting your routes with query parameters included.
  3. pipe: “FreeCodeCamp says” it combines n functions. It’s a pipe flowing left-to-right, calling each function with the output of the last one. This is the main function that works like a conveyor belt. Now you might ask why this is needed but what if I told you that the functions it would combine would be our respective guards. this means if the user request data comes in as an argument the argument is passed through each of the functions (guards) and the output is the processed data that we can use to handle the user. Genius right, that's the power of functional programming.
  4. checkIfVueInstanceOrNuxtContext: This is a bonus function that I use personally to check if the code I am writing is executing on the server runtime (Nuxt Context) or browser runtime (Vue instance). This is necessary because I write my async code as services and reuse them whether on the server or browser but there's a little catch. The catch is when I try to use them on the server it would be behind the “app” property (for instance app.$axios) but on the client, it would be behind the “this” property (for instance this.$axios). So I use that function every time to always separate for each case in the same service method so I don’t write it twice. I hope you find it as convenient as much as I do because it could be a lifesaver if you like to use the same service methods in your asyncData (as it would be executed on both the browser and server runtimes of Nuxt).

With a full understanding of our utility methods, we go down the heart of the application THE MIDDLEWARE. I hope you have been understanding the process so far.

THE MIDDLEWARE

middleware/auth.js

Whew! that is a huge file, let us break it down and it would all make sense. First of all, register the middleware in your nuxt.config.js file. After that is done let us dive in and explain function to function from top to bottom.

  1. routeGuards: This function uses array.reduce in conjunction with the pipe function explained above to basically create a conveyor belt for any data to pass through all the navigation guards. it takes a parameter of all the navigation guards and using “array.reduce” runs the pipe function on each iteration. Makes sense?
  2. ifUser: This function uses our already set up store to basically detect if the user is logged in. Which means if the user is logged in, the store.getters[‘auth/getUser’] should not be an empty string. This is a sample method to show an authentication rule but in a realistic scenario, you can implement whatever checks you want and have as much as possible to cater for all the authentication states of your users.
  3. redirect: This function is very easy but a little tricky. It uses 3 values: to, from and context. The “context” is where the actual redirect functionality of nuxt would be and that's why it is needed. The “to” value signifies the destination of the request. The “from” value which is only available on the browser runtime of nuxt signifies the route the request was before requesting a new route (It makes sense as it is only available on the browser runtime as on the server runtime each request is stateless). Now the tricky part is to prevent a redirection loop. On the browser runtime of nuxt, when redirection occurs the redirected request is passed through the middleware again with updated values before it is sent to Nuxt to display which is unlike the server runtime that is parsed once and sent to the client. Because of this behaviour, we have to use the “isSameURL” function to check if the “to” and “from” entries are the same. You might wonder why the to and from entries are similar during the next iteration, here's why. Let's take a sample request named A, for its first pass its parameters are (to=”/home”, from=”/login”) and the set navigation guards allow it through it would come again for its second pass as (to=”/home”, from=”/home”) and of course, the navigation guards would allow it through just as in its first pass so it is up to our redirect function to prevent another redirection because that would just end up in a redirection loop. This part was the hardest part in this middleware as it was very hard to debug as nuxt would just freeze once it's in a redirect loop.
  4. routeAuthProcessor: This is the entry point of our middleware and it receives the context value which is the single source of truth for every middleware containing all we ever need in the middleware, Heres what it does. It takes the context and prepares the request object understandable by the route guards then sending it over to the routeGuards function explained above for processing then takes it result and passes it to the redirect function above to take action. Now to explain the request object parameters namely: to, destination, processed, and context. “To” is the route path the request is trying to visit before the navigation guards. “Destination” with an initial value of null is going to be configured by the route guards to signify the decided route for the request after passing the navigation guards. “Processed” is a flag used to signify any upcoming navigation guard that this request has been successfully handled by a previous route guard. Finally, as “Context” holds the store and the redirecting functionality, it is required to provide more information to the navigation guards.
  5. routeGuardFunctions: This encompasses the unguarded, initial and guarded route guard functions. The unguarded route guard is a function that would respond to requests that are targeted at public routes in your application. It is necessary to allow hits to routes like login and register. The initial route guard is a function that would respond to hits to the base url for cases that would require an already logged user to be redirected to the home page. The guarded route guard would finally protect all the guarded routes and ensure the right requirements are met for the guarded route. The rule of thumb for every navigation guard is to alter only the processed and destination fields and not act on any data that has the processed field as true. Feel free to create as much navigation guards as per the auth requirements of your application.

That's it, with all the code and explanation of this article you should be with a working prototype of my authentication model. This repository for this example is https://github.com/dop3ch3f/nuxt-auth-tutorial just in case you run into a few bugs or need a template to start from. I hope with this approach you have not only learnt how to use middlewares to set up your own custom authentication but to also use middlewares for anything in Nuxt. I also hope this feature has convinced you on the awesomeness of Nuxt. Happy Hacking

--

--