parse-server: Custom authentication failed: Cannot read property 'authenticate' of undefined

Issue Description

I’m trying to do the custom authentication, but got confused through the insufficient docs. http://docs.parseplatform.org/parse-server/guide/#custom-authentication

Steps to reproduce

Here is my cloud code:

const authmyapp = require('./authmyapp')

Parse.Cloud.define('sign', function(req, res) {
  const user = new Parse.User()
  const authData = {
    myapp: {
      module: authmyapp,
      openid: 'test',
    },
  }
  user._linkWith('weapp', authData).then(userInfo => {
    res.success(userInfo)
  })
})

And to eliminate interference, I made the auth logic like this:

// authmyapp.js

function validateAuthData(authData) {
  return Promise.resolve()
}

function validateAppId() {
  return Promise.resolve()
}

module.exports = {
  validateAppId,
  validateAuthData,
}

Expected Results

A new user signed up with my custom auth-info linked.

Actual Outcome

When running this cloud code, it threw this error on the log:

error: Error generating response. TypeError: Cannot read property 'authenticate' of undefined
    at ParseUser.value (***/node_modules/parse-server/node_modules/parse/lib/node/ParseUser.js:170:18)
    at ***/cloud/main.js:18:8
    at ***/node_modules/parse-server/lib/Routers/FunctionsRouter.js:176:9
    at new Promise (<anonymous>)
.....

Environment Setup

  • Server
    • parse-server version (Be specific! Don’t say ‘latest’.) : 2.7.4
    • Localhost or remote server? (AWS, Heroku, Azure, Digital Ocean, etc): localhost

Correct me if I did something wrong. Thanks. And actually the docs lack many example code to help us figure out.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 15 (13 by maintainers)

Most upvoted comments

Thank you guys! Having looked your explanations and examples, I made my code like this (with the above auth config in the ParseServer Initialization kept):

...
  const user = new Parse.User()
  const authData = {
    weapp: {
      openid: 'test',
    },
  }
  const provider = {
    authenticate(options) {
      options.success(this, {
        openid: 'test',
      })
    },
    getAuthType() {
      return 'weapp'
    },
  }
  user._linkWith(provider, authData).then(userInfo => {
    res.success(userInfo)
  })
...

where I only need to passing the authData directly.

But the error log said

Error generating response. ParseError {
  code: 252,
  message: 'This authentication method is unsupported.' }

After searching for the error generator: https://github.com/parse-community/parse-server/blob/11c40dce97da72271e362e50016500e9f3e3a1ec/src/RestWrite.js#L230 I realized that I need to changed the ‘openid’ to ‘id’. And it works. But I’m not sure if it’s a good way.

And here’s something I still don’t understand:

  1. Where should I place the _registerAuthenticationProvider(provider) if I want to make a one-time initialization?(Like what you said to ‘make the first parameter a string key’.) Do I need to write a file like FacebookUtils.js and import it to some config?
  2. What is the second parameter (authData) in _linkWith used for if I’ve got the provider.authenticate({ success }) { success(this, authData) } in the first parameter to give the auth data? (If I keep the second an empty object, it works as well. But I can’t keep it undefined, otherwise it throw a error.)
  3. Again, the document seems so weak. I tried to make something like adapter to complete this but found it hard to figure it out. Any supplement, simple examples or templates would be appreciate! Have you got any plans on that? Thank you! 😄

The issue with this approach is that any failure will happen very late in the process, at the last step as you’ll gather all infos befor making a single call to your API. Which can lead to hard to debug scenarios. You should probably just do the logIn first, calling parse-server to ensure the auth data is valid, then try to set the username and save immediately, if the username is already taken, you can prompt for another one.

OK, by looking at your error log again, it’s from the Parse client, not server. The ParseUser _linkWith second parameter expects an options object which has authData as its key. So it will look like:

user._linkWith('weapp', {authData})

If it cannot find this key, it will ge to this else block: ParseUser.js#L102

BTW, you could directly use static method on ParseUser, ParseUser.loginWith which essentially call internal _linkWith