1

We're switching from SPA to statically generated, and are running into a problem with middleware.

Basically, when Nuxt is statically rendered, middleware is run on the build server first, and then is run after each page navigation client side. The important point is that middleware is not run client side on first page load. This is discussed here

We work around this for some use cases by creating a plugin that uses the same code, since plugins are run on the first client load.

However, this pattern doesn't work well for this use case. The following is an example of the middleware that we want to use:

// middleware/authenticated.js
export default function ({ store, redirect }) {
  // If the user is not authenticated
  if (!store.state.authenticated) {
    return redirect('/login')
  }
}
// Inside a component
<template>
  <h1>Secret page</h1>
</template>

<script>
  export default {
    middleware: 'authenticated'
  }
</script>

This example is taken directly from the Nuxt docs.

When rendered statically, this middleware is not called on first page load, so a user might end up hitting their dashboard before they've logged in, which causes problems.

To add this to a plugin, the only way I can think to do this is by adding a list of authenticated_routes, which the plugin could compare to and see if the user needs to be authed.

The problem with that solution though is that we'd then need to maintain a relatively complex list of authed pages, and it's made worse by having dynamic routes, which you'd need to match a regex to.

So my question is: How can we run our authenticated middleware, which is page specific, without needing to maintain some list of routes that need to be authenticated? Is there a way to actually get the middleware associated to a route inside a plugin?

Mohsen
  • 4,049
  • 1
  • 31
  • 31
HMilbradt
  • 3,980
  • 16
  • 31
  • Did you tried running the middleware on a page or a layout? Also, there is also the possibility to use a router guard like `beforeRouteEnter`. Meanwhile, to my knowledge, middleware is supposed to work in a `target: static`case.. Do you have `ssr: true` btw? – kissu Jun 25 '21 at 17:27
  • We have SSR set to true, and target static. I've updated the second paragraph with a link which explains that as far as Nuxt is concerned, this is working as intended. We're specifically looking for a way around the need for the middleware/plugin combo. And yes, target=static, ssr=true, which is running the middleware on the build server for the first page load rather than in the client. – HMilbradt Jun 25 '21 at 22:25
  • Hey guys, did you find a solution for that? I have the exact same situation. – Martin Sep 03 '21 at 06:49

1 Answers1

0

To me it is not clear how to solve it the right way. We are just using the static site generation approach. We are not able to run a nuxt middleware for the moment. If we detect further issues with the following approach we have to switch.

One challenge is to login the user on hot reload for protected and unprotected routes. As well as checking the login state when the user switches the tabs. Maybe session has expired while he was on another tab.

We are using two plugins for that. Please, let me know what you think.

authRouteBeforeEnter.js The plugin handles the initial page load for protected routes and checks if the user can access a specific route while navigating around.

import { PROTECTED_ROUTES } from "~/constants/protectedRoutes"

export default ({ app, store }) => {
    app.router.beforeEach(async (to, from, next) => {

        if(to.name === 'logout'){
            await store.dispatch('app/shutdown', {userLogout:true})
            return next('/')
        }

        if(PROTECTED_ROUTES.includes(to.name)){

            if(document.cookie.indexOf('PHPSESSID') === -1){
                await store.dispatch('app/shutdown')
            }

            if(!store.getters['user/isLoggedIn']){

                await store.dispatch('user/isAuthenticated', {msg: 'from before enter plugin'})

                console.log('user is logged 2nd try: ' + store.getters['user/isLoggedIn'])
                return next()
            }
            else {

                /**
                 * All fine, let him enter
                 */

                return next()
            }
        }

        return next()
    })
 }

authRouterReady.js This plugin ment for auto login the user on unprotected routes on initial page load dnd check if there is another authRequest required to the backend.

import { PROTECTED_ROUTES } from "~/constants/protectedRoutes";
export default function ({ app, store }) {
    app.router.onReady(async (route) => {

        if(PROTECTED_ROUTES.includes(route.name)){

            // Let authRouterBeforeEnter.js do the job
            // to avoid two isAuthorized requests to the backend
            await store.dispatch('app/createVisibilityChangedEvent')

        }
        else {

            // If this route is public do the full init process
            await store.dispatch('app/init')

        }
    })
}

Additionally i have added an app module to the store. It does a full init process with auth request and adding a visibility changed event or just adds the event.

export default {
  async init({ dispatch }) {
    dispatch('user/isAuthenticated', {}, {root:true})
    dispatch('createVisibilityChangedEvent')
  },
  async shutdown({ dispatch }, {userLogout}) {
    dispatch('user/logout', {userLogout}, {root:true})
  },
  async createVisibilityChangedEvent({ dispatch }) {
    window.addEventListener('visibilitychange', async () => {
      if (document.visibilityState === 'visible') {
        console.log('visible changed');
        await dispatch('user/isAuthenticated', {}, {root:true})
      }
    })
  },
}
Martin
  • 217
  • 3
  • 3
  • My last paragraph highlights this, but we really want to avoid maintaining any kind of static list of protected routes. There's a number of reasons for this, but IMO the number one is that this is something the framework should deal with more gracefully. I've opened an issue on the Nuxt Github repo to hopefully get some responses from their core team. – HMilbradt Sep 12 '21 at 23:41
  • https://github.com/nuxt/nuxt.js/issues/9473 Link here for the Github issue, although it's been open for a while and received no responses yet – HMilbradt Sep 12 '21 at 23:42
  • Maybe it helps to create a protected routes file during the build process. – Martin Sep 14 '21 at 02:57