Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to save JWT Token in Vuex with Nuxt Auth Module?

I am currently trying to convert a VueJS page to NuxtJS with VueJS. Unfortunately I have some problems with authenticating the user and I can't find a solution in Google. I only use Nuxt for the client. The API is completely separate in express and works with the existing VueJS site.

In Nuxt I send now with the Auth module a request with username and password to my express Server/Api. The Api receives the data, checks it, and finds the account in MongoDB. This works exactly as it should. Or as I think it should. Now I take the user object and generate the jwt from it. I can debug everything up to here and it works. Now I probably just don't know how to keep debugging it. I send an answer with res.json(user, token) back to the Nuxt client (code follows below). As I said, in my current VueJS page I can handle this as well. Also in the Nuxt page I see the answer in the dev console and to my knowledge the answer fits.

Now some code. The login part on the express Api:


    const User = require('../models/User')
    const jwt = require('jsonwebtoken')
    const config = require('../config/config')

    function jwtSignUser(user){
        const ONE_YEAR = 60 * 60 * 24 * 365
        return jwt.sign(user,config.authentication.jwtSecret, {
            expiresIn: ONE_YEAR
        })
    }
    module.exports = {
        async login (req, res){
            console.log(req.body)
            try{
                const {username, password} = req.body
                const user = await User.findOne({
                    username: username
                })

                if(!user){
                    return res.status(403).send({
                        error: `The login information was incorrect.`
                    })
                }

                const isPasswordValid = await user.comparePassword(password)
                if(!isPasswordValid) {
                    return res.status(403).send({
                        error: `The login information was incorrect.`
                    })
                }

                const userJson = user.toJSON()
                res.json({
                    user: userJson,
                    token: jwtSignUser(userJson)
                })

            } catch (err) {
                console.log(err)
                res.status(500).send({
                    error: `An error has occured trying to log in.`
                })
            }
        }
    }

nuxt.config.js:


    auth: {
        strategies: {
          local: {
            endpoints: {
              login: {url: '/login', method: 'post' },
              user: {url: '/user', method: 'get' },
              logout: false,
            }
          }
        },
        redirect: {
          login: '/profile',
          logout: '/',
          user: '/profile',
          callback:'/'
        }
      }

even tried it with nearly any possible "propertyName".

and, last but not least, the method on my login.vue:



    async login() {
          try {
            console.log('Logging in...')
            await this.$auth.loginWith('local', {
              data: {
                "username": this.username,
                "password": this.password
              }
            }).catch(e => {
              console.log('Failed Logging In');
            })
            if (this.$auth.loggedIn) {
              console.log('Successfully Logged In');
            }
          }catch (e) {        
            console.log('Username or Password wrong');
            console.log('Error: ', e);
          }
        }

What I really don't understand here... I always get "Loggin in..." displayed in the console. None of the error messages.

I get 4 new entries in the "Network" Tag in Chrome Dev Tools every time I make a request (press the Login Button). Two times "login" and directly afterwards two times "user".

The first "login" entry is as follow (in the General Headers):

Request URL: http://localhost:3001/login
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: [::1]:3001
Referrer Policy: no-referrer-when-downgrade

The first "user" entry:

Request URL: http://localhost:3001/user
Request Method: OPTIONS
Status Code: 204 No Content
Remote Address: [::1]:3001
Referrer Policy: no-referrer-when-downgrade

Both without any Response.

The second login entry:

Request URL: http://localhost:3001/login
Request Method: POST
Status Code: 200 OK
Remote Address: [::1]:3001
Referrer Policy: no-referrer-when-downgrade

and the Response is the object with the token and the user object.

The second user entry:

Request URL: http://localhost:3001/user
Request Method: GET
Status Code: 200 OK
Remote Address: [::1]:3001
Referrer Policy: no-referrer-when-downgrade

and the Response is the user object.

I think for the login should only the login request be relevant, or I'm wrong? And the user request works because the client has asked for the user route and the user route, always send the answer with the actual user object in my Express API.

Because I think, the problem is in the login response? Here some screenshots from the Network Tab in Chrome Dev Tools with the Request/Response for login.

First login request without response
Second login request
Response to second login request

Do I have to do something with my Vuex Store? I never found any configured Vuex Stores in examples for using the Auth Module while using google so I thougt I do not have to change here anything.

Thats my Vuex Store (Vue Dev Tools in Chrome) after trying to login without success:

{"navbar":false,"token":null,"user":null,"isUserLoggedIn":false,"access":false,"auth":{"user":"__vue_devtool_undefined__","loggedIn":false,"strategy":"local","busy":false},"feedType":"popular"}

There is also some logic I use for my actual VueJS site. I will remove that when the Auth Module is working.

Asked by @imreBoersma : My /user endpoint on Express looks like:


    app.get('/user', 
            isAuthenticated,
            UsersController.getUser)

I first check if the User is authenticated:


    const passport = require('passport')

    module.exports = function (req, res, next) {
        passport.authenticate('jwt', function (err, user) {
            if(err || !user) {
                res.status(403).send({
                    error: 'You are not authorized to do this.'
                })
            } else {
                req.user = user
                next()
            }
        })(req, res, next)
    }

After that I search the User document in MongoDB and send the document to the client:


    const User = require('../models/User')

    module.exports = {
        [...]
        getUser (req, res) {
            User.findById(req.user._id, function (error, user){
                if (error) { console.error(error); }
                res.send(user)
            })
        }
        [...]

    }

Feel free to ask for more information.

like image 283
Jakob Kühne Avatar asked May 04 '19 19:05

Jakob Kühne


1 Answers

I think I can answer my own question.

I searched the whole time for an error regarding to my api response. The problem was the "propertyName" on user endpoint in the nuxt.config.js.

It is set to "user" as default. When I set it to "propertyName: false", than everything works as it should.

 auth: {
    strategies: {
      local: {
        endpoints: {
          login: {url: '/login', method: 'post', propertyName: 'token' },
          user: {url: '/user', method: 'get', propertyName: false },
          logout: false,
        }
      }
    }
  },
like image 108
Jakob Kühne Avatar answered Oct 30 '22 02:10

Jakob Kühne