Skip to content

Error 206 cannot modify user for new Facebook user #6511

Open
@ashish-naik

Description

@ashish-naik

Hello

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 
    }
  },

Activity

henrytkirk

henrytkirk commented on Mar 22, 2020

@henrytkirk

I'm having a similar issue too - perhaps related:
If I login with Facebook successfully, then logout and try Sign-in with Apple using the same email associated with Facebook, I get a 500 returned - internal server error.

dplewis

dplewis commented on Mar 22, 2020

@dplewis
Member

@henrytkirk Can you open a new issue and fill out the template. Any logs or sample code would help.

dplewis

dplewis commented on Mar 22, 2020

@dplewis
Member

@ashish-naik Can you try facebook login on the backend with masterKey: true?

ashish-naik

ashish-naik commented on Mar 22, 2020

@ashish-naik
Author

I am not using cloud code for login. Call from swift code.

dplewis

dplewis commented on Mar 22, 2020

@dplewis
Member

I wanted you to try it and see if that would fix this

If login is successful does your current user have a sessionToken? To change a user you need to have permission to do so.

ashish-naik

ashish-naik commented on Mar 23, 2020

@ashish-naik
Author

I will try. May take some time due to workplace priorities.

Yes sessionToken is nil after successful login.

ashish-naik

ashish-naik commented on Mar 25, 2020

@ashish-naik
Author

@dplewis 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.

Does above help?

ashish-naik

ashish-naik commented on Mar 29, 2020

@ashish-naik
Author

@dplewis Did you get a chance to look at my code?

Hope you are safe and doing well in this difficult times.

dplewis

dplewis commented on Mar 29, 2020

@dplewis
Member

I can look into it, can you open a similar post in the iOS SDK?

ashish-naik

ashish-naik commented on Mar 30, 2020

@ashish-naik
Author
ashish-naik

ashish-naik commented on Apr 9, 2020

@ashish-naik
Author

@dplewis I had opened 1477 post awhile back for Sign in with Apple. The symptoms are same as Facebook login issue that i created for you to look at. I have added some details of investigation there but realized it is marked closed. Can you please have a look? Should i remove the details from there and repost here?

ashish-naik

ashish-naik commented on Apr 11, 2020

@ashish-naik
Author

@dplewis did you get a chance to check? Although you asked me to open this issue in iOS SDK repo (which i did, linked above), i think this has to do with server.

I am stuck at this since many days. Really appreciate if you could take a look.

Today i tested on local server on my Mac with same config as Heroku ie
npm v 6.13.7
node v 9.4.0
parse server 4.2.0

it worked on local but didnt on Heroku. I noticed that this.storage['authprovider'] is undefined in createSessionTokenIfNeeded to createSessionToken() isnt called.

RestWrite.prototype.createSessionTokenIfNeeded = function() {

logger.info('Message - createSessionTokenIfNeeded - For class - ' + this.className)
  if (this.className !== '_User') {
    return;
  }
  // Don't generate session for updating user (this.query is set) unless authData exists
  if (this.query && !this.data.authData) {
    return;
  }
  logger.info('Message - createSessionTokenIfNeeded - Not update call - going ahead')

  // Don't generate new sessionToken if linking via sessionToken
  if (this.auth.user && this.data.authData) {
    return;
  }
  logger.info('Message - createSessionTokenIfNeeded - not linking so going ahead')

  if (
    !this.storage['authProvider'] && // signup call, with (THIS IS FAILING)
    this.config.preventLoginWithUnverifiedEmail && // no login without verification
    this.config.verifyUserEmails
  ) {
    // verification is on
    logger.info('Message - createSessionTokenIfNeeded - returning as no auth provider, preventLoginWihoutEmail, verifyEmail')   
    logger.info('Message - createSessionTokenIfNeeded - authProvider = ' + this.storage['authProvider'] + ' preventLoginWihoutEmail = ' + this.config.preventLoginWithUnverifiedEmail + ' verifyUserEmails = ' + this.config.verifyUserEmails)
    return; // do not create the session token in that case!
  }
  logger.info('Message - createSessionTokenIfNeeded - before calling - return this.createSessionToken()' )

  return this.createSessionToken();
};

35 remaining items

ashish-naik

ashish-naik commented on Dec 18, 2022

@ashish-naik
Author

Realised setting verifyUserEmails was incorrect.

tried below but gives error Unhandled promise rejection: Error: Function requires an adapter
How to fix it?

it('test facebook signup with verifyUserEmails=true', done => {

    reconfigureServer({
      appName: 'unused',
      verifyUserEmails: true,
      publicServerURL: 'http://localhost:8378/1',
    })
    .then(() => {

      const data = {
        authData: {
          facebook: {
            id: '8675309',
            access_token: 'jenny',
          },
        },
      };
      let newUserSignedUpByFacebookObjectId;
      rest
        .create(config, auth.nobody(config), '_User', data)
        .then(r => {
          expect(typeof r.response.objectId).toEqual('string');
          expect(typeof r.response.createdAt).toEqual('string');
          expect(typeof r.response.sessionToken).toEqual('string');
          newUserSignedUpByFacebookObjectId = r.response.objectId;
          return rest.create(config, auth.nobody(config), '_User', data);
        })
        .then(r => {
          expect(typeof r.response.objectId).toEqual('string');
          expect(typeof r.response.createdAt).toEqual('string');
          expect(typeof r.response.username).toEqual('string');
          expect(typeof r.response.updatedAt).toEqual('string');
          expect(r.response.objectId).toEqual(newUserSignedUpByFacebookObjectId);
          return rest.find(config, auth.master(config), '_Session', {
            sessionToken: r.response.sessionToken,
          });
        })
        .then(response => {
          expect(response.results.length).toEqual(1);
          const output = response.results[0];
          expect(output.user.objectId).toEqual(newUserSignedUpByFacebookObjectId);
          done();
        })
        .catch(err => {
          jfail(err);
          done();
        });
    });
    
  })
mtrezza

mtrezza commented on Dec 18, 2022

@mtrezza
Member

On which line does it throw that?

ashish-naik

ashish-naik commented on Dec 19, 2022

@ashish-naik
Author

Line where PublicServerURL is mentioned.

ashish-naik

ashish-naik commented on Dec 20, 2022

@ashish-naik
Author

I fixed the error by adding adapter constant.

The test passes successfully so wondering why actual code is failing and work with my fix explained above.
Am i missing something in configuring the test to emulate the scenario?

it('test facebook signup with verifyUserEmails=true', done => {

   const emailAdapter = {
     sendVerificationEmail: options => {
       sendEmailOptions = options;
     },
     sendPasswordResetEmail: () => Promise.resolve(),
     sendMail: () => {},
   };


   reconfigureServer({
     appName: 'unused',
     verifyUserEmails: true,
     emailAdapter: emailAdapter,
     emailVerifyTokenValidityDuration: 0.5, 
     publicServerURL: 'http://localhost:8378/1',
   })
   .then(() => {

     const data = {
       authData: {
         facebook: {
           id: '8675309',
           access_token: 'jenny',
         },
       },
     };
     let newUserSignedUpByFacebookObjectId;
     rest
       .create(config, auth.nobody(config), '_User', data)
       .then(r => {
         console.warn('Error206: New FB user created ' + r.response.objectId);

         expect(typeof r.response.objectId).toEqual('string');
         expect(typeof r.response.createdAt).toEqual('string');
         expect(typeof r.response.sessionToken).toEqual('string');
         newUserSignedUpByFacebookObjectId = r.response.objectId;
         return rest.create(config, auth.nobody(config), '_User', data);
       })
       .then(r => {
         console.warn('Error206: FB user queried ' + r.response.objectId);

         expect(typeof r.response.objectId).toEqual('string');
         expect(typeof r.response.createdAt).toEqual('string');
         expect(typeof r.response.username).toEqual('string');
         expect(typeof r.response.updatedAt).toEqual('string');
         expect(r.response.objectId).toEqual(newUserSignedUpByFacebookObjectId);
         return rest.find(config, auth.master(config), '_Session', {
           sessionToken: r.response.sessionToken,
         });
       })
       .then(response => {
         expect(response.results.length).toEqual(1);
         const output = response.results[0];
         expect(output.user.objectId).toEqual(newUserSignedUpByFacebookObjectId);
         done();
       })
       .catch(err => {
         jfail(err);
         done();
       });
   });
   
 })
ashish-naik

ashish-naik commented on Aug 29, 2023

@ashish-naik
Author

I got error on version 5.5.4 also. I haven't changed my app's login code.

However don't get error if i run on my Mac that has same version of Parse Server, NodeJS, npm as on Digital Ocean.
Only change between two setup is, Digital Ocean App platform uses Heroku build pack. I used to get same error on Heroku also on past build packs also. Not sure if this changes anything.

mtrezza

mtrezza commented on Aug 29, 2023

@mtrezza
Member

What version of Parse Server are you using? If this issue cannot be reproduced on Parse Server 6, we'll go ahead and close this issue, since PS5 doesn't receive any support anymore other than security related issues, and even that only 4 more months.

ashish-naik

ashish-naik commented on Aug 30, 2023

@ashish-naik
Author

Upgraded server to 6.2.1 and still got error. On local.

Works if preventLoginWithUnverifiedEmail: false works but fails if preventLoginWithUnverifiedEmail: true

By the way, unrelated question but running this in index.js fails. Asking because i am not able to deploy on Digital Ocean so unable to test. Appreciate if you can point the mistake. World in prior to v5

const autoWithDrawRequestJob = schedule.scheduleJob({rule: '* * 0 * *', tz: "Asia/Kolkata"}, function(){
  console.log('Running resetPriceDropDate job');
  Parse.Cloud.run("cloudJob",null,{useMasterKey:true});
});
ashish-naik

ashish-naik commented on Sep 2, 2023

@ashish-naik
Author

Correction : I get error irrespective of value set for preventLoginWithUnverifiedEmail on both local or Digital ocean.

mtrezza

mtrezza commented on Sep 2, 2023

@mtrezza
Member

This thread has gotten quite long. I'd suggest to first identify whether it's a Parse Server, Parse SDK, or non-Parse issue. To do this let's boil this issue down into a failing test in a pull request, using the Parse JS SDK. The test should also help others to understand the issue. It seems you have already written a test. Please try to further reduce the test if possible and remove any code or special config that is not necessary for the test to fail (like email adapter, etc.). Use the standard APIs of the Parse JS SDK, no REST APIs. Don't reconfigure the server if not necessary, or reconfigure only with the options you need to change. Use async/await syntax, no chained promises. Please take a look at other auth-related tests how they are written and adapt for your issue. We will then see in our CI with a plain Parse Server config whether this is reproducible.

ashish-naik

ashish-naik commented on Sep 3, 2023

@ashish-naik
Author

I ran the test under server on latest version and it ran without failing. My original test also succeeded. Worked after removing all additional config too.

I cloned JS SDK, ran the default tests.
I am not well versed with JS so not sure where all i have to change in my test below.

it('test async facebook signup with verifyUserEmails=true', async done => {
    const emailAdapter = {
      sendVerificationEmail: options => {
        sendEmailOptions = options;
      },
      sendPasswordResetEmail: () => Promise.resolve(),
      sendMail: () => {},
    };


    await reconfigureServer({
      appName: 'unused',
      verifyUserEmails: false,
      emailAdapter: emailAdapter,
      emailVerifyTokenValidityDuration: 0.5, // 0.5 second
      publicServerURL: 'http://localhost:8378/1',
    })

      const data = {
        authData: {
          facebook: {
            id: '8675309',
            access_token: 'jenny',
          },
        },
      };

    let newUserSignedUpByFacebookObjectId;
    rest
      .create(config, auth.nobody(config), '_User', data)
      .then(r => {
        expect(typeof r.response.objectId).toEqual('string');
        expect(typeof r.response.createdAt).toEqual('string');
        expect(typeof r.response.sessionToken).toEqual('string');
        newUserSignedUpByFacebookObjectId = r.response.objectId;
        return rest.create(config, auth.nobody(config), '_User', data);
      })
      .then(r => {
        expect(typeof r.response.objectId).toEqual('string');
        expect(typeof r.response.createdAt).toEqual('string');
        expect(typeof r.response.username).toEqual('string');
        expect(typeof r.response.updatedAt).toEqual('string');
        expect(r.response.objectId).toEqual(newUserSignedUpByFacebookObjectId);
        return rest.find(config, auth.master(config), '_Session', {
          sessionToken: r.response.sessionToken,
        });
      })
      .then(response => {
        expect(response.results.length).toEqual(1);
        const output = response.results[0];
        expect(output.user.objectId).toEqual(newUserSignedUpByFacebookObjectId);
        done();
      })
      .catch(err => {
        jfail(err);
        done();
      });

  });
mtrezza

mtrezza commented on Sep 3, 2023

@mtrezza
Member

Could you please open a PR and try to make the changes suggested in my previous comment? Some suggestions are not test specific, like using away/async instead of chained promises and removing code that is unnecessary for the failing test. We can then continue the discussion in the PR to adapt the test. If we cannot reproduce the issue, we cannot investigate this issue further and we have to assume a custom configuration on your side being the cause for this.

ashish-naik

ashish-naik commented on Sep 4, 2023

@ashish-naik
Author

Created PR #8737

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @henrytkirk@davimacedo@ashish-naik@mtrezza@dplewis

      Issue actions

        Error 206 cannot modify user for new Facebook user · Issue #6511 · parse-community/parse-server