Nuxtjs Auth module not working in the middleware

14,140

Solution 1

had the same problem, and I solved it now with a lot of trial & error.

The server side had no knowledge of the loggedIn state, because they did not implement it(?).

So I created my own middleware that sets the state for the server side.

Create: middleware/auth-ssr.ts

import { Context, Middleware } from '@nuxt/types';
import { parse as parseCookie } from 'cookie';
import jsonwebtoken from 'jsonwebtoken';
import { IJwtPayload } from '../../api/_types/types';

/**
 * This middleware is needed when running with SSR
 * it checks if the token in cookie is set and injects it into the nuxtjs/auth module
 * otherwise it will redirect to login
 * @param context
 */
const debugAuthMiddleware: Middleware = async (context: Context) => {
  if (process.server && context.req.headers.cookie != null) {
    try {
      const cookies = parseCookie(context.req.headers.cookie);
      const token = cookies['auth._token.local'] || '';
      const tokenWithoutBearer = token.replace('Bearer ', '');
      // console.log('headers.cookie token', token);
      // console.log('debugAuthMiddleware $auth 1', context.$auth.$state);
      if (!token || token.includes('false')) {
        // sometimes it stores 'Bearer false' when it unsets
        return;
      }
      const jwt: IJwtPayload = (jsonwebtoken.decode(tokenWithoutBearer) as unknown) as IJwtPayload;
      // console.log('jwt payload', jwt);
      if (!jwt) {
        return;
      }
      // console.log('set token ✅', jwt);
      await context.$auth.setToken('locale', tokenWithoutBearer);
      await context.$auth.setUser(jwt);
      context.$auth.$state.loggedIn = true;
    } catch (e) {
      console.error('debugAuthMiddleware', e);
    }
    // console.log('debugAuthMiddleware $auth 2', context.$auth.$state);
  }
};

export default debugAuthMiddleware;

then in nuxt.config.ts I have this middleware:

router: {
    middleware: ['user-agent', 'auth-ssr', 'auth'],
},

and this my auth config:

auth: {
    redirect: {
      logout: '/?signedOut=1',
      home: '/dashboard',
    },
    strategies: {
      local: {
        endpoints: {
          login: { url: '/api/v1/auth/login', method: 'post', propertyName: 'token' },
          logout: { url: '/api/v1/auth/logout', method: 'post' },
          user: { url: '/api/v1/user', method: 'get', propertyName: 'user' },
        },
        autoFetchUser: false, // do not fetch automatically! user object is coming from login api call
        rewriteRedirects: true, // If enabled, user will redirect back to the original guarded route instead of redirect.home.
        fullPathRedirect: true, // If true, use the full route path with query parameters for redirect
      },
    },
  },

Then the server side nodejs/auth-middleware gets the correct loggedIn state + user (my JWT token includes userId, email, name, scope: []).

Solution 2

Unfortunately I wasn't able to make nuxtjs/auth work in the middleware but I was able to solve the issue by using cookie-universal-nuxt in combination with nuxtjs/auth:

You can leave your axios version as it is, no need to downgrade for this solution

  1. npm install --save cookie-universal-nuxt
  2. add cookie-universal-nuxt in your nuxt.config.js file:
modules: [
    // other modules ...
    '@nuxtjs/auth',
    'cookie-universal-nuxt',
  ],
  1. create a custom auth middleware. I called mine auth-user in the middleware folder:
export default async function ({ app, redirect }) {
  // the following look directly for the cookie created by nuxtjs/auth
  // instead of using $auth.loggedIn
  const user = await app.$cookies.get('auth._token.local')
  if (user) {
    // let the user see the page
  } else {
    // redirect to homepage
    redirect('/')
  }
}
  1. then declare your middleware in the root page of your application that you want to be accessible only by authenticated users:
<script>
export default {
  middleware: ['auth-user'],
}
</script>

If this doesn't work, check the cookie name where your user credential are saved by opening the developer tools / inspector in the browser.

Share:
14,140

Related videos on Youtube

Fabio Magarelli
Author by

Fabio Magarelli

I'm a software developer with experience in Healthcare and Research. I like working remotely most of the time but also have the opportunity to meet my team in the office (wherever that may be). I am eager to learn and have no problem stepping out of my comfort zone in order to achieve my goals.

Updated on June 04, 2022

Comments

  • Fabio Magarelli
    Fabio Magarelli almost 2 years

    Hi I found an old question similar to mine with no answer on StackOverFlow : nuxtjs/auth axios not sending cookie

    Also here on GitHub, without a valid solution: https://github.com/nuxt-community/auth-module/issues/478

    So the problem is that if I call $auth.loggedIn in any page, it works like a charm but if I do it in my custom authentication middleware (or if I use the default auth middleware), it always return false.

    my auth configuration in nuxt.config.js

    auth: {
        strategies: {
          local: {
            endpoints: {
              login: {
                url: '/rest-auth/login/',
                method: 'post',
                propertyName: 'key',
              },
              logout: { url: '/rest-auth/logout/', method: 'post' },
              user: {
                url: '/rest-auth/user/',
                method: 'get',
                propertyName: false,
              },
            },
            tokenType: 'Token',
            tokenName: 'Authorization',
          },
          redirect: {
            login: '/user_dashboard',
            home: '/',
          },
        },
      },
    

    my custom auth middleware

    export default async function ({ $auth, redirect }) {
      const user = await $auth.loggedIn
      console.log(user) // <-- this always return false for some reason :(
      if (user) {
        // let the user see the page
      } else {
        // redirect to homepage
        redirect('/')
      }
    }
    

    EDIT:

    As requested, this is my package.json:

    {
      "name": "<MY_APP_NAME>",
      "version": "1.0.0",
      "private": true,
      "scripts": {
        "dev": "nuxt",
        "build": "nuxt build",
        "start": "nuxt start",
        "generate": "nuxt generate",
        "lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .",
        "lint:style": "stylelint **/*.{vue,css} --ignore-path .gitignore",
        "lint": "npm run lint:js && npm run lint:style",
        "test": "jest"
      },
      "lint-staged": {
        "*.{js,vue}": "eslint",
        "*.{css,vue}": "stylelint"
      },
      "husky": {
        "hooks": {
          "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
          "pre-commit": "lint-staged"
        }
      },
      "dependencies": {
        "@nuxt/content": "^1.9.0",
        "@nuxtjs/auth": "^4.9.1",
        "@nuxtjs/axios": "^5.12.2",
        "@nuxtjs/pwa": "^3.0.2",
        "cookie-universal-nuxt": "^2.1.4",
        "core-js": "^3.6.5",
        "nuxt": "^2.14.7",
        "nuxt-buefy": "^0.4.3"
      },
      "devDependencies": {
        "@commitlint/cli": "^11.0.0",
        "@commitlint/config-conventional": "^11.0.0",
        "@nuxtjs/eslint-config": "^3.1.0",
        "@nuxtjs/eslint-module": "^3.0.0",
        "@nuxtjs/style-resources": "^1.0.0",
        "@nuxtjs/stylelint-module": "^4.0.0",
        "@vue/test-utils": "^1.1.0",
        "babel-core": "7.0.0-bridge.0",
        "babel-eslint": "^10.1.0",
        "babel-jest": "^26.5.0",
        "eslint": "^7.10.0",
        "eslint-config-prettier": "^6.12.0",
        "eslint-plugin-nuxt": "^1.0.0",
        "eslint-plugin-prettier": "^3.1.4",
        "husky": "^4.3.0",
        "jest": "^26.5.0",
        "lint-staged": "^10.4.0",
        "node-sass": "^4.14.1",
        "prettier": "^2.1.2",
        "sass-loader": "^10.0.3",
        "stylelint": "^13.7.2",
        "stylelint-config-prettier": "^8.0.2",
        "stylelint-config-standard": "^20.0.0",
        "vue-jest": "^3.0.4"
      }
    }
    
    
    • nathan1658
      nathan1658 over 3 years
      Hi seems I’ve solved the case by downgrade the nuxt/axios module, can you share your package.json? Maybe I can have a look on mine and compare it.
    • Fabio Magarelli
      Fabio Magarelli over 3 years
      @nathan1658 sure, see edit on the question
    • Fabio Magarelli
      Fabio Magarelli over 3 years
      @nathan1658 following your suggestion, I found this issue: github.com/nuxt-community/auth-module/issues/853 so I'm trying downgrading axios with: npm install @nuxtjs/[email protected]. wish me luck.
    • Fabio Magarelli
      Fabio Magarelli over 3 years
      still not working
    • nathan1658
      nathan1658 over 3 years
      Hi sorry for late reply, I have the same version with yours. Can you check the secure setting on the cookie i.e. set it to false when debugging on http?
  • Fabio Magarelli
    Fabio Magarelli over 3 years
    This seems a lot of work but probably is a more proper way of solving the issue. good job!
  • phips28
    phips28 over 3 years
    Imo this should be implemented directly within nuxtjs/auth to male this work out of the box for SSR. Maybe I have time in the future to propose a PR. Or someone else sees this and implements it ;)
  • Iman Shafiei
    Iman Shafiei almost 3 years
    Sharing codes and examples would always be helpful.