adonisjs / auth

Official Authentication package for AdonisJS
https://docs.adonisjs.com/guides/auth/introduction
MIT License
196 stars 63 forks source link

request.authUser is undefined #88

Closed mfgabriel92 closed 6 years ago

mfgabriel92 commented 6 years ago

I'm still using legacy version, and my application uses API tokens for authentication, therefore I would have to make use of request.authUser to be able to access the logged in user, but it's returning undefined for me.

I checked the initial configuration in auth.js, it matches what's said in the documentation. I also generate a token when the user logs in, with request.auth.generate(user), but even though, when checking for a logged in user with request.auth.check(), it returns false, and everything else is undefined.

When the login operation is executed, this method below will execute before generating a token:

  * accessToken() {
    let isValid = yield this.validate()

    if (!isValid) {
      return
    }

    const user = yield User.query().where('email', this.email).with(...).first()

    if (!user) {
      this.addError(HTTPResponse.STATUS_NOT_FOUND, 'The user does not exist')

      return false
    }

    const userProperties = yield user.userProperties().fetch()
    const hash = _.find(userProperties.toJSON(), { key: 'hash' })
    const salt = _.find(userProperties.toJSON(), { key: 'salt' })
    const passwordHash = hash.value
    const passwordSalt = salt.value
    const userPassword = this.password + passwordSalt
    const isPasswordVerified = yield Hash.verify(userPassword, passwordHash)

    if (!isPasswordVerified) {
      this.addError(HTTPResponse.STATUS_UNAUTHORIZED, 'Invalid username or password')

      return false
    }

    return user
  }

Which then returns the User to the controller, allowing the generation of the token:

  * accessToken(request, response) {
    const authOperation = new AuthOperation()

    authOperation.email = request.input('email')
    authOperation.password = request.input('password')

    let user = yield authOperation.accessToken()

    if (!user) {
      let error = authOperation.getFirstError()
      throw new HttpException(error.message, error.code)
    }

    let token = yield request.auth.generate(user);

    response.send({
      user,
      token: token.token
    })
  }

I also confirmed the accessToken value storing the user's token from the database when checking Networking tab on Google Chrome.

RomainLanz commented 6 years ago

Hey @mfgabriel92! 👋

Are you sending the token from your client with the correct format to each request after being authenticated?

mfgabriel92 commented 6 years ago

Hi @RomainLanz,

I am not sure. How would I do it? I have this following Redux action that triggers the methods above:

export function login ({ email, password }) {
  return {
    [CALL_API]: {
      endpoint: '/api/auth/access-token',
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email,
        password
      }),
      types: [
        LOGIN,
        {
          type: LOGIN_SUCCESS,
          meta: {
            done: true,
            transition: {
              success: (prevState, nextState, res) => {
                return {
                  pathname: '/dashboard'
                }
              }
            }
          }
        },
        LOGIN_FAIL
      ]
    }
  }
}
RomainLanz commented 6 years ago

By using the Authorization HTTP header.

mfgabriel92 commented 6 years ago

Hi, @RomainLanz

Nothing. I am sending the Authorization header to the method I am requesting, but it still is undefined.

return dispatch({
  [CALL_API]: {
    endpoint,
    method: 'GET',
    headers: {
      'Authorization': `Bearer ${accessToken}`
    },
    types: [ GET_ALL_GIGS, GET_ALL_GIGS_SUCCESS, GET_ALL_GIGS_FAIL ]
  }
});

By logging out request.auth, the user object is also null.

   ....
    options: 
    { serializer: 'Lucid',
      model: 'App/Model/Token',
      scheme: 'api',
      expiry: '1d' },
   user: null },
user: null }

This causes the .middleware('auth') to fail, saying the login failed, followed with the message:

(node:20533) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: You may only yield a function, promise, generator, array, or object, but the following object was passed: "undefined"

RomainLanz commented 6 years ago

Have you checked from devtools that you are correctly sending the token?

mfgabriel92 commented 6 years ago

Yes. I found out that I hadn't set up the accessToken when login is successful. This caused the error, because I saw that the token stored was different from the one newly generated.