Skip to content

Error 206 cannot modify user for new Facebook user #1492

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ashish-naik opened this issue Mar 30, 2020 · 34 comments
Closed

Error 206 cannot modify user for new Facebook user #1492

ashish-naik opened this issue Mar 30, 2020 · 34 comments

Comments

@ashish-naik
Copy link

@dplewis As you suggested i have created issue here.

I am getting error 206 after new Facebook user is saved and reason seems to be nil sessionToken.
I am facing this for Apple sign in also randomly. This is probably getting fixed by #6416. Don't know whether Facebook issue will also be fixed.

I have one old account created on Heroku Parse server which works fine ie i am able to save attributes after login.

I was running server v3.9.0. tried upgrading till 4.0.2 but still failing.

I am updating PFUser object post login locally in iOS client using Swift. Not using cloud code for this.

Also failing on back4app v3.9.0. Sign in with Apple also failing on back4app but works randomly.

Works on local setup consistently. Local server installed using bootstrap.sh script.

I have seen some issued dated 2016 fixing this error but server code seems to have changed lot so cannot view the same code referred in #952

using FBSDKCoreKit 5.15.1, FBSDKLoginKit 5.15.1

Steps to reproduce
on iOS, Try login using a facebook account that is not yet created on Parse.
Running iOS 13.3.1

Expected Results
After successful login, should be able to save other attributes in PFUser.current() object

Actual Outcome
The login is successful but saving any attributes fails with error 206 "cannot modify user xxxxx"
Fails on back4app also. v3.9.0
Both Apple and Facebook new user registration and update work fine in local environment.

Environment Setup
Server

parse-server version (Be specific! Don't say 'latest'.) : 3.9.0 to 4.0.2 (Local 3.10.0)
Operating System: heroku-18 (Local MacOS 10.15.3)
Hardware: heroku-18 (Local MacOS 10.15.3)
Localhost or remote server? (AWS, Heroku, Azure, Digital Ocean, etc): Both as mentioned above
Database

MongoDB version: mLab 3.6.12 (Local 4.2.3)
Storage engine: mLab
Hardware: mLab
Localhost or remote server? (AWS, mLab, ObjectRocket, Digital Ocean, etc): both
Logs/Trace
Mar 15 02:51:40 yovl app/web.1 error: Parse error: Cannot modify user kc30Xbk1wA. {"code":206,"stack":"Error: Cannot modify user kc30Xbk1wA.\n at RestWrite.runDatabaseOperation (/app/node_modules/parse-server/lib/RestWrite.js:1170:11)\n at /app/node_modules/parse-server/lib/RestWrite.js:127:17\n at processTicksAndRejections (internal/process/task_queues.js:97:5)"}

package.json used for deployment to Heroku

{
  "name": "parse-server-example",
  "version": "1.4.0",
  "description": "Based on example Parse API server using the parse-server module",
  "main": "index.js",
  "repository": {
    "type": "git",
    "url": "https://github.com/ashish-naik/parse-server.git"
  },
  "license": "MIT",
  "dependencies": {
    "express": "4.17.1",
    "parse-server": "4.1.0",
    "underscore":"*",
    "parse": "2.11.0"
  },
  "scripts": {
    "start": "node index.js"
  },
  "engines": {
    "node": ">= 8",
    "npm": ">= 5.7.1"
  }
}
auth section in index.js

auth: {
    facebook: {
      appIds: process.env.FACEBOOK_APP_ID
    },
    apple: {
      
      client_id: process.env.IOS_BUNDLE_ID 
    }
  },

I tried below. Not good with cloud code so hope code is not wrong.

Cloud function

Parse.Cloud.define("loginWithFacebook", function(request) {

  var params = request.params
  var authData = params.authData
  var id = params.id
  var expiredBy = params.expiredBy

  var facebookAuthData = {
    "id": id,
    "access_token": authData,
    "expiration_date": expiredBy
  }

  Parse.FacebookUtils.logIn(facebookAuthData, { useMasterKey: true }) 
    .then(function(user) {
        if (user.isNew()) {
            console.log("NEW User logged in with id " + user.id + " with session token : " + user.sessionToken)
        } else {
          console.log("Existing User logged in with id " + user.id + " with session token : " + user.sessionToken)
        }
    })
    .catch(function(error) {
      console.log('ERROR','loginWithFacebook() - Error with facebook login : '+ error);
      throw error
    })
  
})

ios Code

func processFBLogin() {
        
        if let accessToken = AccessToken.current {
            
            logger.debug("Facebook user logged in with toke \(accessToken.appID)- \(accessToken.tokenString)")
            
            PFCloud.callFunction(inBackground: "loginWithFacebook", withParameters: ["id":accessToken.userID, "authData":accessToken.tokenString, "expiredBy":accessToken.expirationDate], block: {
                
                (response: Any?, error: Error?) -> Void in
                
                if error == nil {

                    if let loggedinUser = PFUser.current() {
                        logger.debug("FB login successful - sessiontoken \(loggedinUser.sessionToken) ")
                    } else {
                        
                        logger.debug("FB login failed ")
                        
                    }

                } else {
                    
                    logger.error("Error with facebook login \(String(describing: error?.localizedDescription))")
                }
            })
            
        } else {
            
            logger.info("No FB token available")
        }

    }

Server log

info: Ran cloud function loginWithFacebook for user undefined with:
   Input: {"id":"xxxxxxxxxx","expiredBy":"2020-05-24T15:48:42.018Z","authData":"adasdasdasdasdasdasda"}
   Result: undefined {"functionName":"loginWithFacebook","params":{"id":"xxxxxxxxxx","expiredBy":"2020-05-24T15:48:42.018Z","authData":"adasdasdasdasdasdasda"}}
 verbose: RESPONSE from [POST] /parse/functions/loginWithFacebook: {
   "response": {}
 } {"result":{"response":{}}}
 verbose: REQUEST for [POST] /parse/users: {
   "authData": {
     "facebook": {
       "id": "xxxxxxxxxx",
       "access_token": "adasdasdasdasdasdasda",
       "expiration_date": {
         "__type": "Date",
         "iso": "2020-05-24T15:48:42.018Z"
       }
     }
   }
 } {"method":"POST","url":"/parse/users","headers":{"host":"myApp.herokuapp.com","connection":"close","user-agent":"node-XMLHttpRequest, Parse/js2.11.0 (NodeJS 13.11.0)","accept":"*/*","content-type":"text/plain","x-request-id":"c9ec003f-70c6-4b03-bb2e-acbda997836b","x-forwarded-for":"54.92.152.225","x-forwarded-proto":"https","x-forwarded-port":"443","via":"1.1 vegur","connect-time":"1","x-request-start":"1585152709435","total-route-time":"0","content-length":"569"},"body":{"authData":{"facebook":{"id":"xxxxxx","access_token":"adasdasdasdasdasdasda","expiration_date":{"__type":"Date","iso":"2020-05-24T15:48:42.018Z"}}}}}
 heroku/router at=info method=POST path="/parse/functions/loginWithFacebook" host=myApp.herokuapp.com request_id=2d5de5a0-f465-4387-aa7a-e4c3f575566c fwd="122.169.14.163" dyno=web.1 connect=1ms service=14ms status=200 bytes=625 protocol=https
 heroku/router at=info method=POST path="/parse/users" host=myApp.herokuapp.com request_id=c9ec003f-70c6-4b03-bb2e-acbda997836b fwd="54.92.152.225" dyno=web.1 connect=1ms service=298ms status=201 bytes=794 protocol=https
 verbose: RESPONSE from [POST] /parse/users: {
   "status": 201,
   "response": {
     "objectId": "efsyICJCAq",
     "createdAt": "2020-03-25T16:11:49.440Z",
     "username": "hDTtBCA6oSpZGDR7a9kpemoFC"
   },
   "location": "http://myApp.herokuapp.com/parse/users/efsyICJCAq"
 } {"result":{"status":201,"response":{"objectId":"efsyICJCAq","createdAt":"2020-03-25T16:11:49.440Z","username":"sdfsdfsdfsdf"},"location":"http://myApp.herokuapp.com/parse/users/efsyICJCAq"}}
 Existing User logged in with id efsyICJCAq with session token : undefined

if i run code for a registered user without master key, i get sessionToken printed in logs.

But i am getting undefined for sessionToken for user.sessionToken or user.getsessionToken.
Not sure to fetch access token.

Moreover, in Xcode i get PFUser.current as nil.

By the way, i had created similar issue for Sign in With Apple also. #1477

@noobs2ninjas
Copy link
Member

noobs2ninjas commented Apr 13, 2020

Ok. I think you're making this a little more complicated than it is. Seems to me the cloud login is unnecessary. You have two choices with how to do this automatically right within the parse on iOS.

First, if you include ParseFacebookUtils aka pod 'Parse/FacebookUtils' you can:

a) Do it manually with the access tokens

[PFFacebookUtils logInInBackgroundWithAccessToken:accessToken
                                            block:^(PFUser *user, NSError *error) {
  if (!user) {
    NSLog(@"Uh oh. There was an error logging in.");
  } else {
    NSLog(@"User logged in through Facebook!");
  }
}];

b) Have parse do the facebook login with the user automatically. This will automatically bring up the window. Have them authorize. Create a user that will become currentUser. You can still do user.isNew() to do further registration if you'd like.

[PFFacebookUtils logInInBackgroundWithReadPermissions:permissions block:^(PFUser *user, NSError *error) {
  if (!user) {
    NSLog(@"Uh oh. The user cancelled the Facebook login.");
  } else if (user.isNew) {
    NSLog(@"User signed up and logged in through Facebook!");
  } else {
    NSLog(@"User logged in through Facebook!");
  }
}];

If this isnt easy enough and you want to insist on using cloud code. Youll need to login on the cloud, have the cloud function pass back the session token. Then do something like this.


--Cloud
Parse.FacebookUtils.logIn(facebookAuthData, { useMasterKey: true }) 
    .then(function(user) {
        if (user != null) {
           return ["sessionToken" : user.sessionToken]
       }
    }) .catch(function(error) {
      console.log('ERROR','loginWithFacebook() - Error with facebook login : '+ error);
      throw error
    })

--iOS
PFCloud.callFunction(inBackground: "loginWithFacebook", withParameters: ["id":accessToken.userID, "authData":accessToken.tokenString, "expiredBy":accessToken.expirationDate], block: { (response: Any?, error: Error?) -> Void in
            if let sessionToken = response["sessionToken"] as? String {
                PFUser.become(inBackground: sessionToken) { (user, error) in
                    if user != nil {
                        print(PFUser.current()?.username)
                    }
                }
            }
        })

I honestly would ditch the cloud code on this one. I use cloud functions a ton but this is just built in so nice and neat that all we can really do is add more complexity and make it easier to break. Stick to the native functions and you'll be amazed how super simple it is.

Also, if you do use carthage or cocoapods it automatically loads the facebook SDK. To set it up to work with parse automatically simply follow this . Then on your login page just do the

[PFFacebookUtils logInInBackgroundWithReadPermissions:permissions block:^(PFUser *user, NSError *error) {
  if (!user) {
    NSLog(@"Uh oh. The user cancelled the Facebook login.");
  } else if (user.isNew) {
    NSLog(@"User signed up and logged in through Facebook!");
  } else {
    NSLog(@"User logged in through Facebook!");
  }
}];

Automatically sets current user. Adds token to the new user the first time they log in. Also, you can use parse's library to link and unlink facebook.

One thing I'd like to point out is that Apple now requires you to offer Apple Sign In, if you allow any other 3rd party oAuth. As in, they will reject your app if you dont add it too. We are currently working on adding it to ParseUI and also have its own module. So, that should be coming shortly.

@ashish-naik
Copy link
Author

ashish-naik commented Apr 13, 2020

No, I am not using cloud code. I am using Facebook iOS sdk method and it was working fine.

@dplewis had asked me to try out cloud code so that’s just test code.

I have done some digging. Pls check issue parse-community/parse-server#6511

And I have coded Sign In with Apple also and that too is failing because this same reason.

@noobs2ninjas
Copy link
Member

Ok @ashish-naik ok I get the basic idea. First like me ask two things. 1) is there already an anonymous or previous user prior to this? 2) the returned/current user is not null. It just wont let you make any changes to it. You get that error instead right? Just making sure I understand.

@ashish-naik
Copy link
Author

  1. I tried login after logout and even with fresh install of app. Not using anonymous user.
  2. Correct. It is not null.

@noobs2ninjas
Copy link
Member

Ok so quick question not sure if you use dashboard. Kinda makes these things easier but if not no big deal.

So, in the cloud code. We do sessionToken on console.log("NEW User logged in with id " + user.id + " with session token : " + user.sessionToken)?

@noobs2ninjas
Copy link
Member

Also, this occurs weather this process creates a new Parse user or not correct?

@noobs2ninjas
Copy link
Member

noobs2ninjas commented Apr 13, 2020

I find this a bit weird

Message - createSessionTokenIfNeeded - For class - _User
Message - createSessionTokenIfNeeded - Not update call - going ahead for _User
Message - createSessionTokenIfNeeded - not linking so going ahead for _User
Message - createSessionTokenIfNeeded - returning as no auth provider, preventLoginWihoutEmail, verifyEmail for _User
Message - createSessionTokenIfNeeded - authProvider = undefined preventLoginWihoutEmail = true

Primarily the "returning as no auth provider"
on the cloud what happens when you do JSON.stringify(user);
Just want to see what all it has.

@ashish-naik
Copy link
Author

Also, this occurs weather this process creates a new Parse user or not correct?

Yes new user is created.
I use dashboard.

I didn’t understand previous question abt console.log

@noobs2ninjas
Copy link
Member

Heres your cloud code for logging in using facebook. I'm wondering if session token prints here.

Parse.FacebookUtils.logIn(facebookAuthData, { useMasterKey: true })
.then(function(user) {
if (user.isNew()) {
console.log("NEW User logged in with id " + user.id + " with session token : " + user.sessionToken)
} else {
console.log("Existing User logged in with id " + user.id + " with session token : " + user.sessionToken)
}
})

@ashish-naik
Copy link
Author

No it doesnt print.

and you want me to use JSON.stringify(user); in console.log in cloud code? Havent used it before.

@noobs2ninjas
Copy link
Member

Yea user is just a Javascript Object which should break down and show you everything associated with that user. So, really quick. The end goal here is to create a new user with the facebook auth data. Right?

@ashish-naik
Copy link
Author

I got this

verbose: RESPONSE from [POST] /parse/users: {
  "status": 201,
  "response": {
    "objectId": "tm8yajowSZ",
    "createdAt": "2020-04-13T19:22:03.843Z",
    "username": "xz2EsFqJZyUcb9ycD6X9dLT6d"
  },
  "location": "https://yovl.herokuapp.com/parse/users/tm8yajowSZ"
} {"result":{"status":201,"response":{"objectId":"tm8yajowSZ","createdAt":"2020-04-13T19:22:03.843Z","username":"xz2EsFqJZyUcb9ycD6X9dLT6d"},"location":"https://yovl.herokuapp.com/parse/users/tm8yajowSZ"}}
Existing User logged in with id tm8yajowSZ with session token : undefined
JSON.stringify(user) - {"authData":{"facebook":{"id":"226097261637656","access_token":"EAAGsGGVceOIBAJEZAsyoa2LZCgXwyYhcXaXZBZBwrtrgXpXxGSUyKyoqkSWNWZA4ks2qAH481ZB6QPZBkE6cnbF1ZCPF3hLJ2WpvqETfspPIguJ6fx2dsSZADJJsuL5vj2b1Aa078mf6x4E3DFOcTIqZAro9lsA5AOo3ytcP9W7GVmpGOiTm1CZAQ4lKoL8cZBmcDXZBQT57rUCMF0GZBTc2QsoVotXKWsg0LZBzkvdWvBmLslJMAZDZD","expiration_date":{"__type":"Date","iso":"2020-06-12T19:07:20.054Z"}}},"createdAt":"2020-04-13T19:22:03.843Z","username":"xz2EsFqJZyUcb9ycD6X9dLT6d","updatedAt":"2020-04-13T19:22:03.843Z","objectId":"tm8yajowSZ"}

@noobs2ninjas
Copy link
Member

So heres whats happening. I think there is no sessionToken necessarily being created because theres no device to link the session to. Its either it figures accessToken already has a expiration date which is as good as a session token anyway. or they arent creating it because this is done in Cloud code can be called by about anything. Also, cloud code isnt going to automatically respond with the user information either way. So I have an Idea that I think might sort this all out doing it natively that not only will create the session token but also Either way. I think I got your solution. Combines what you did in cloud but does it natively so that currentUser can be set automatically.

let user = PFUser()
        var facebookAuthData = [
          "id": id,
          "access_token": authData,
          "expiration_date": expiredBy
        ]
        user.linkWithAuthType(inBackground: "facebook", authData: facebookAuthData)
        user.saveInBackground { (saved, error) in
            if saved {
                print(PFUser.current()?.sessionToken)
            }
        }

Try signing up this way and see what happens.

@noobs2ninjas
Copy link
Member

noobs2ninjas commented Apr 13, 2020

If that doesnt work the way it should try this.

user.signUpInBackground { (completed, error) in
                    if completed {
                        print(PFUser.current()?.sessionToken)
                    }
                }

@noobs2ninjas
Copy link
Member

My bet one of the two will work once the save or signup is completed. Also, good news. You shouldnt need to use master key doing this natively.

@ashish-naik
Copy link
Author

linkWith resulted in error

User cannot be saved unless they are already signed up. Call signUp first.
I replaced user.saveInBackground after linkWith and got below error.
Cannot sign up without a password.

@noobs2ninjas
Copy link
Member

noobs2ninjas commented Apr 13, 2020

Yea try this one.
change saveInBackground with signUpInBackground.

user.signUpInBackground { (completed, error) in
if completed {
print(PFUser.current()?.sessionToken)
}
}

@ashish-naik
Copy link
Author

i got error that username needs to be set so did user.username = accessToken.userID

and then got error Cannot sign up without a password.

@ashish-naik
Copy link
Author

ashish-naik commented Apr 13, 2020

it is well past midnight for me in India so I will have to pause now.

Let me know what else to try. Will pickup tomorrow.

@noobs2ninjas
Copy link
Member

Once this next release is out I'm going to impliment a way to make this simple.

Try this when you get a chance.

var facebookAuthData = [
          "id": id,
          "access_token": authData,
          "expiration_date": expiredBy
        ]
 let task: BFTask<PFUser> = PFUser.logInWithAuthType(inBackground: "facebook", authData: facebookAuthData)
        task.continueWith { (user) -> Any? in
            if task.isCompleted {
                print("yay")
            } else if task.isCancelled {
                print("canceled")
            } else if user.error {
                print(user.error?.localizedDescription)
            }
        }

@noobs2ninjas
Copy link
Member

If this doesnt work Ill have to dig through the FacebookUtils to see what they do with the data to make it work. I think this should work though.

@ashish-naik
Copy link
Author

ashish-naik commented Apr 14, 2020

Didnt work.

this print("yay \(task.result!.sessionToken)") produced yay nil

Below is heroku log

before return this.getUserAndRoleACL()
before return this.validateClientClassCreation()
before return this.handleInstallation()
before return this.handleSession()
before return this.validateAuthData()
validateAuthData - is a _User class with valid username
validateAuthData - auth method supported. Going ahead
validateAuthData - provider = facebook
validateAuthData - Abt to call handleAuthData with auData [object Object]
findUsersWithAuthData - providers length 1providers - facebook
findUsersWithAuthData - queryKey authData.facebook.id
findUsersWithAuthData - authData[provider].id 226097261637656
findUsersWithAuthData - query.length 1
findUsersWithAuthData - findPromise length undefined
findUsersWithAuthData - before return findPromise
handleAuthData - Results count is 0
before return this.runBeforeSaveTrigger()
before return this.deleteEmailResetTokenIfNeeded()
before return this.validateSchema()
before return this.setRequiredFieldsIfNeeded()
before return this.transformUser()
before return this.expandFilesForExistingObjects()
before return this.destroyDuplicatedSessions()
before return this.runDatabaseOperation()
before return this.createSessionTokenIfNeeded()
createSessionTokenIfNeeded - For class - _User
createSessionTokenIfNeeded - Not update call - going ahead for _User
createSessionTokenIfNeeded - not linking so going ahead for _User
createSessionTokenIfNeeded - returning as no auth provider, preventLoginWihoutEmail, verifyEmail for _User
createSessionTokenIfNeeded - authProvider = undefined preventLoginWihoutEmail = true verifyUserEmails = true for _User
before return this.handleFollowup()
before return this.runAfterSaveTrigger()
before return this.cleanUserAuthData()
before return this.response()

Before you dig into FacebookUtils, i want to highlight that same issue is happening for Apple with in also so doubt this is FacebookUtils related.

I am wondering why findUsersWithAuthData returns no data. is it trying to find just created _User object via POST? if so then i have a feeling that findUsersWithAuthData is called before creation. I may be naive because this is most basic core functionality but i am also intrigued.

Noticed one more thing, with your above code, validateAuthData is called once and not twice if you check log in my other post 6411.

@noobs2ninjas
Copy link
Member

God bless Heroku logs. I found your problem. Should have thought of this before.

preventLoginWihoutEmail = true 
verifyUserEmails = true for _User

So, your configuration on the server is that you require not only an email on the account to login, but verification of that email. Neither of which you are doing in your cloud code or natively when you pass the objectId back. So the user is saving. You can query that user with that auth data. However it wont log in until those restrictions are met.

Just till you get this working and add a registration page to add their email, turn them both off. After that lets try it again and let me know if there is any difference.

Btw..with the way we setup that task it automatically passes the user back as the argument in the closure once the task is complete.

 task.continueWith { (user) -> Any? in
    if task.isCompleted {
        print(user.sessionToken)
    }
}

Although, the email settings are issues, I'd like to reiterate this is so much easier using "Parse/FacebookUtils" native submodule for the iOS sdk. Its basically a helper built around the Facebook SDK. Everything you want to do authenticate with facebook, automatically create a new user with session token using authentication data(and email if you want) with email verification, can be done in about 10-20 lines of code. In fact Facebook literally helped with making the native FacebookUtils submodule for Parse during the time they owned Parse Platform. It streamlines everything and makes it all really simple.

Even linking. Using Parse/FacebookUtils for iOS, you can allow linking facebook later literally 3 lines of code. Lets say a user is already registered with password/email or username. Add a button for linking facebook and it all happens automatically just running.

PFFacebookUtils.linkUserInBackground(user, withReadPermissions: nil, { 
(succeeded: Bool?, error: NSError?) -> Void in
    if succeeded {
      print("Woohoo, the user is linked with Facebook!")
    }
})

Facebook sign in window or app opens, allowing the user to authenticate and accept any permissions requested, its returns to the app passes back the auth data, adds it to the current user, and saves it all in 3-6 lines of code. It would take quadruple the amount of code just using the facebook SDK and adding it to the user manually. Anyway, something to think about. Even graph requests are easier.

Anyway, temporarily change those configuration settings, make sure this works, then turn them back on when you implement a way to have the user input and verify their email during this process.

Hit me back if you have any questions and let me know how it goes!

@ashish-naik
Copy link
Author

So i commented verifyUserEmails and tried sign up for both Facebook and Apple and it worked.

Although, the email settings are issues, I'd like to reiterate this is so much easier using "Parse/FacebookUtils" native submodule for the iOS sdk.

i am using Parse/FacebookUtils for iOS which is super simple as you mentioned and use PFUser.logInWithAuthType(inBackground: authType, authData: authData).continueWith { task -> Any? for Sign in With Apple.
Cloud sign up code is just for troubleshooting this issue.

With verifyUserEmails removed, i am able to sign up successfully using Facebook and Apple and not getting error 206 also because session token is generated. See log below.

before return this.validateAuthData()
validateAuthData - is a _User class with valid username
validateAuthData - auth method supported. Going ahead
validateAuthData - provider = facebook
validateAuthData - Abt to call handleAuthData with auData [object Object]
findUsersWithAuthData - providers length 1providers - facebook
findUsersWithAuthData - queryKey authData.facebook.id
findUsersWithAuthData - authData[provider].id 226097261637656
findUsersWithAuthData - query.length 1
findUsersWithAuthData - findPromise length undefined
findUsersWithAuthData - before return findPromise
handleAuthData - Results count is 0
before return this.runBeforeSaveTrigger()
before return this.deleteEmailResetTokenIfNeeded()
before return this.validateSchema()
before return this.setRequiredFieldsIfNeeded()
before return this.transformUser()
before return this.expandFilesForExistingObjects()
before return this.destroyDuplicatedSessions()
before return this.runDatabaseOperation()
before return this.createSessionTokenIfNeeded()
createSessionTokenIfNeeded - For class - _User
createSessionTokenIfNeeded - Not update call - going ahead  for _User
createSessionTokenIfNeeded - not linking so going ahead  for _User
createSessionTokenIfNeeded - before calling - return this.createSessionToken()  for _User
createSessionToken = async function()
Auth.js - token generated - r:da251a2f99662848043612bf9ed2a930

I have three ways of sign up: Facebook, Apple and Email/Password.
I assume verifyUserEmails is required only for email based sign up so why is it interfering with third party authentication?

I have tested that email verification works when user signs up using email when verifyUserEmails is enabled hence i didnt understand your below comment.

make sure this works, then turn them back on when you implement a way to have the user input and verify their email during this process.

@ashish-naik
Copy link
Author

And I didn’t use cloud code for testing after removing f verifyEmail option. I have used my original code that use Parse/facebookUtils.

@noobs2ninjas
Copy link
Member

Perfect! Glad ya got that going. I think you are correct that email verification is for email based signup only. Cant remember specifically testing that but I've been using Parse for so long with email verification and 3rd party oAuth that I imagine I'd know if that wasnt the case. Now that we just got 1.18.0 out we're probably going to be working on getting Apple Sign In integrated into Parse for our next release. Just something to watch for.

@ashish-naik
Copy link
Author

Hi Nathan, congratulations on new release and thanks for helping with figuring out the issue.

However, I want to use email verification for users signing up using without auth. How to go about that?

I found a post that was left unsolved i guess. Not exactly for this issue but related so just mentioning here because i may need this as well. or was this addressed?
parse-community/parse-server#4041

I have tried to explain the probable and cause and fix below.

When findUsersWithAuthData returns no result which means this user had not signed up earlier, below handleAuthDataValidation block handles auth validation and returns success since it is a valid auth.

return this.handleAuthDataValidation(authData).then(() => {
      if (results.length > 1) {
        // More than 1 user with the passed id's
        throw new Parse.Error(
          Parse.Error.ACCOUNT_ALREADY_LINKED,
          'this auth is already used'
        );
      } 
    });

But in this flow, this.storage['authProvider'] is not set so below if statement in createSessionTokenIfNeeded evaluates to true and returns without calling this.createSessionToken().

if (
    !this.storage['authProvider'] && // signup call, with
    this.config.preventLoginWithUnverifiedEmail && // no login without verification
    this.config.verifyUserEmails
  ) {
    // verification is on
    return; // do not create the session token in that case!
  }
  return this.createSessionToken();

So i tried this fix
Move this line

this.storage['authProvider'] = Object.keys(authData).join(',');

from inside

if (results.length == 1) {

to just before it.
and then set verifyUserEmails back to true.

After this change sign up with facebook and login both worked, sign up and login with email also worked. I have not added function for linkWith in my app so cannot test it yet.

is this is a valid solution?

@ashish-naik
Copy link
Author

@noobs2ninjas Appreciate if you could check my above comments.

@ashish-naik
Copy link
Author

@dplewis For error 206 i have been facing, i changed the code as above and my error went away.

is this a correct fix? Could you please take a look?

@stale
Copy link

stale bot commented Jun 26, 2020

This issue has been automatically marked as stale because it has not had recent activity. If you believe it should stay open, please let us know! As always, we encourage contributions, check out the Contributing Guide

@stale stale bot added the Won't Fix label Jun 26, 2020
@stale stale bot closed this as completed Jul 3, 2020
@Jagadeeshwar-Reddy
Copy link

@ashish-naik Did you manage to find a solution for this ?
I have been experiencing the same issue using the native Signin for facebook & google & apple Signin options. I have parse server 4.2 running in cloud.

@ashish-naik
Copy link
Author

Check parse-community/parse-server#6511

I am waiting for someone from Parse team to check the solution Working for me.

@Jagadeeshwar-Reddy
Copy link

Jagadeeshwar-Reddy commented Aug 21, 2020

@ashish-naik Thanks for the quick response.

Strangely to me, turning off the "Prevent login if email is not verified" feature made the Social sign in work.

I'm planning to implement a "beforeSave Trigger" for a user signing with auth data and update the "emailVerified" to true as a temporary fix until we get a proper fix from the sdk.

@ashish-naik
Copy link
Author

Don't think you can update that but give it a try.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants