Skip to content

Every facebook login creates a new user #934

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
rafapetter opened this issue Mar 9, 2016 · 46 comments · Fixed by #952
Closed

Every facebook login creates a new user #934

rafapetter opened this issue Mar 9, 2016 · 46 comments · Fixed by #952

Comments

@rafapetter
Copy link

Issue
Every time I try to login through facebook a new user is created on mongo. I've also noticed there's no column _auth_data_facebook saved on these users.

Prerequisites

  • I've migrated to AWS Elastic Beanstalk(64bit Amazon Linux 2015.09 v2.0.7, running Node.js 4.2.3) and MongoLab
  • I'm running the 2.1.4 of Parse Server.
  • I'm testing on Android SDK

Steps to reproduce on Android

  • I've changed the endpoint from parse API to my parse server
  • Installed the app
  • Tried to facebook login
  • After successful facebook authentication a new user is created on mongo with no auth data.

Log from Verbose
Here we can see that authData is sent through POST

POST /parse/users { host: 'parseserver-xxxx-env.elasticbeanstalk.com',
  'x-real-ip': 'xxxxx',
  'x-forwarded-for': xxxxx',
  'content-length': '326',
  'accept-encoding': 'gzip',
  'content-type': 'application/json',
  'user-agent': 'Parse Android SDK 1.13.0 (com.xxx.xxxx/7) API Level 21',
  'x-newrelic-id': 'xxxxx==',
  'x-parse-app-build-version': '7',
  'x-parse-app-display-version': 'xxxx',
  'x-parse-application-id': 'xxx',
  'x-parse-client-key': 'xxx',
  'x-parse-client-version': 'a1.13.0',
  'x-parse-installation-id': 'xxxxx',
  'x-parse-os-version': '5.0.2',
  'x-forwarded-port': '80',
  'x-forwarded-proto': 'http' } {
  "authData": {
    "facebook": {
      "access_token": "xxxxxxxxxx",
      "expiration_date": "2016-05-08T16:31:45.008Z",
      "id": "xxxxxxxxx"
    }
  }
}

Possible Similar Issues

@flovilmart
Copy link
Contributor

This is totally normal that authData is stored as _auth_data_facebook in mongodb.

Can you make sure, there is never a POST /users with "authData": {
"facebook": null
}

Does this problem occurs after setting a property on the user?

@flovilmart flovilmart reopened this Mar 9, 2016
@rafapetter
Copy link
Author

Ok, but I'm saying that there's no column _auth_data_facebook.

I've searched the entire log for this "facebook": null, and it only occurs on GET calls from username/password logins. So to facebook login POST calls this never happen.

The problem occurs weather I set a property or not, I've tested both cases. I assume it's a problem during the ParseFacebookUtils.logInWithReadPermissionsInBackground call in which the user authdata format is being handled different from how is done on Parse API.

@flovilmart
Copy link
Contributor

when you run with VERBOSE=1 and do ParseFacebookUtils.logInWithReadPermissionsInBackground, what is the request that you have. (GET or POST)

Then you say:

I've searched the entire log for this "facebook": null, and it only occurs on GET calls from username/password logins. So to facebook login POST calls this never happen.

This is really important, that means that the Facebook auth gets unlinked when you call login. Could you provide the logs when running VERBOSE=1 as well for this case?

@rafapetter
Copy link
Author

Ok, I'm gonna show you 2 cases: 1) user login with facebook for the first time; 2) reinstall app, and the same user try to login again with facebook

1) Login is successful, but missing the authData on mongodb. Here's the Verbose sequence:

POST /parse/users { host: 'parseserver-xxxx-env.elasticbeanstalk.com',
  'x-forwarded-proto': 'http' } {
  "authData": {
    "facebook": {
      "access_token": "xxxxx",
      "expiration_date": "2016-05-08T16:31:45.428Z",
      "id": "xxxxxxx"
    }
  }
}
response: {
  "status": 201,
  "response": {
    "objectId": "xxxxxx",
    "createdAt": "2016-03-09T18:38:40.328Z",
    "sessionToken": "r:xxxxxxxxxx"
  },
  "location": "http://parseserver-xxxxx-env.elasticbeanstalk.com/parse/users/xxxxxx"
}

GET /parse/classes/_User/xxxxx { host: 'parseserver-xxx-env.elasticbeanstalk.com',
  'x-forwarded-proto': 'http' } {}
response: {
  "response": {
    "objectId": "xxxxxx",
    "sessionToken": "r:xxxxxxx"
  }
}

2) Login is successful, but a new user is created on mongodb. Here's the Verbose sequence:

POST /parse/users { host: 'parseserver-xxxx-env.elasticbeanstalk.com',
  'x-forwarded-proto': 'http' } {
  "authData": {
    "facebook": {
      "access_token": "xxxx",
      "expiration_date": "2016-05-08T16:31:45.378Z",
      "id": "xxxx"
    }
  }
}
response: {
  "status": 201,
  "response": {
    "objectId": "xxxxx",
    "createdAt": "2016-03-09T18:41:06.368Z",
    "sessionToken": "xxxxxx"
  },
  "location": "http://parseserver-xxxx-env.elasticbeanstalk.com/parse/users/xxxxx"
}

GET /parse/classes/_User/xxxxx { host: 'parseserver-xxxx-env.elasticbeanstalk.com',
  'x-forwarded-proto': 'http' } {}
response: {
  "response": {
    "objectId": "xxxx",
    "sessionToken": "r:xxxxx"
   }
}

@DrBeak1
Copy link

DrBeak1 commented Mar 9, 2016

Something weird is happening for sure with Facebook signup/login. I'm getting similar issues trying to login/auth via ios. I have parse-server running on heroku, using the most up-to-date versions of both the parse-ios cocoapod and parse-server.

From what I can tell when I auth w/Facebook I can see that PFFacebookPrivateUtilities (an ios class) is returning valid credentials, but those credentials never make it to mongoDB.

I've found that (a) removing any beforeSave calls in cloud code stops the issue of duplicate users being created when trying to auth with the same Facebook account however, (b) once a user logs in with Facebook they cannot do anything with their associated objects (i.e., edit their user name, edit owned objects, etc); parse returns the error: 'cannot modify user xxxxxxx'. For more details you can see my ticket: #880

@rafapetter
Copy link
Author

Hi @DrBeak1, yep I'm having the same issue on iOS too.

@DrBeak1
Copy link

DrBeak1 commented Mar 10, 2016

Still an issue with parse-server 2.1.5

@flovilmart
Copy link
Contributor

@DrBeak1 your problem is on iOS right? What method do you use for login?

@flovilmart
Copy link
Contributor

@weengo I'm not sure about Android. in case 1) is Parse.User.currentUser() set correctly? Can you access it's objectId? does the objectId match with what you see in the logs? does the session token match with what you see in the logs?

That may be easier to debug for you if you were running locally from the repository directly.
So far, I've tried different things in unit tests, and I can't reproduce at all this issue.

@DrBeak1
Copy link

DrBeak1 commented Mar 10, 2016

Hey @flovilmart -

Using ParseFacebookUtilsV4 (1.11.1):
logInInBackgroundWithReadPermissions: -- and I'm requesting email, user_location, and user_friends

This method succeeds, returning a user with the correct objectId, a new session token, and an access token for facebook (may be old, it matches the old one stored on my user obj in mongodb. but the one on mongodb is not being updated because my users updatedAt field is a few days old). However, this data does not get relayed to mongoDB. If I go there after login, I can see that the session token is different for this user. Therefore, any attempts to modify user owned data afterwards fails with the 'cannot modify user user_id'

@michaelbina
Copy link

I think this is related to my other issue #755

@tanmays
Copy link

tanmays commented Mar 10, 2016

@flovilmart

This is totally normal that authData is stored as _auth_data_facebook in mongodb.

Can you make sure, there is never a POST /users with "authData": {
"facebook": null
}

I pass authData: {"twitter": null} to unlink a twitter account according to this doc.

For users that have unlinked and linked again database contains _auth_data_twitter as well as authData, where authData is shown as "twitter": null and _auth_data_twitter is correctly populated. However in parse dashboard authData column is incorrectly populated as "twitter": null

Accounts that have not been previously unlinked have only _auth_data_twitter field, the authData field is absent on mongolab database browser in these cases. In the parse dashboard authData column is correctly populated in this case.

This does not cause any issue for me and everything is still working correctly. I think the authData dict should be removed after an unlink request has been passed so that when user links again the parse dashboard will correctly populate the authData field.

@flovilmart
Copy link
Contributor

I just opened #952 that include a 'small' refactoring of the OAuth procedure, as I uncovered a series of weird things there. For the ones running on a local server, please checkout that branch, and run against it.

We definitely could remove the authData dict when you unlink, we could also delete the key

@rafapetter
Copy link
Author

@flovilmart, regarding your questions

@weengo I'm not sure about Android. in case 1) is Parse.User.currentUser() set correctly? Can you access it's objectId? does the objectId match with what you see in the logs? does the session token match with what you see in the logs?

  • Parse.User.currentUser() is set correctly
  • I can access objectId
  • Both objectId and sesstionToken match in the logs

One thing I noticed: _Installation is only created on mongodb after the user signup, is that the normal?

Sure I can test locally, is there a tutorial on how to set up locally?

@flovilmart
Copy link
Contributor

Let's focus on authentication, not throwing more things in there.
You can setup locally following those instructions:

git clone https://github.com/parseplatform/parse-server
cd parse-server
npm install

And then follow those instructions
https://github.com/ParsePlatform/parse-server#standalone-parse-server

Don't forget to pass --databaseURI and all relevant options.

If you wish you can create a JSON configuration and use it like that:

npm start -- path/to/config.json

@flovilmart
Copy link
Contributor

Once you've setup your config, I encourage you to test with that branch flovilmart.OAuthImprovements

in the parse-server folder that you clone:

git fetch
git checkout flovilmart.OAuthImprovements
git pull

and restart the server

@rafapetter
Copy link
Author

@flovilmart Ok, everything is setup:

appId: xxxxxxxx
masterKey: ***REDACTED***
port: 1337
databaseURI: mongodb://[email protected]:xxxxxxxx/xxxxxxxx
serverURL: http://localhost:1337/parse/
mountPath: /parse
maxUploadSize: 20mb

parse-server running on http://localhost:1337/parse/

On android I have changed the endpoint to .server("http://localhost:1337/parse/").build() is that right?

I have reinstalled the app, but can't login. What am I doing wrong?

@flovilmart
Copy link
Contributor

you may have to use ngrok to tunnel the android SDK request to you localhost.

@rafapetter
Copy link
Author

I'm getting 502 Bad Gateway, any idea?
screen shot 2016-03-10 at 1 25 02 pm

@flovilmart
Copy link
Contributor

how did you configure android? can you map the naked xxxx.ngrok.io -> localhost:1337 instead of /parse?

@rafapetter
Copy link
Author

Android endpoint is like this .server("http://27eace14.ngrok.io/").build()

I'm now getting this
screen shot 2016-03-10 at 1 37 36 pm

@flovilmart
Copy link
Contributor

Try With /parse at The end in the android, then maybe start parse-server your server with VERBOSE=1

@rafapetter
Copy link
Author

how do you set VERBOSE=1 on local server?

@rafapetter
Copy link
Author

Couldn't set the verbose, but I got this from ngrok inspection

POST /parse/users

{
    "authData": {
        "facebook": {
            "access_token": "xxxxxx",
            "expiration_date": "2016-05-09T16:37:56.983Z",
            "id": "xxxx"
        }
    }
}

404 Not Found Response

{
    "code": 101,
    "error": "Facebook auth is not configured."
}

@Scoup
Copy link

Scoup commented Mar 10, 2016

I'm saw some strange thing in Facebook login with Android, using anonymous user, this is the login put:

{ authData: { facebook: { access_token: 'CAAIiZCWEGSusBAB8XIiKQU3vxc5R2ZA7DWDI5SBS0sJ7T5eFvCuxshmQRjTe82BXtbZCeYjg9ilZBbZBdcw5D6LG5FZBnRP7UZBSJoLAAE1dnKuTZCPdtjZBlIumDNvqlrm7qoNZAcIbYiZBK6qxIGecUmYiZBrMOc5js0nvR8evBYZC0LiVrq2wBbmPFq1zi7loxU3xdxh7h0gpvXT52ORVQLL1IjZBz7LMfwMZCH09ZC0BOeTQhAZDZD', expiration_date: '2016-05-08T18:19:20.000Z', id: '10207247385845217' } }, objectId: '5DeGfe43PC' }

The objectId is sent because the user exists (anonymous). Then it's try to do a PUT in /parse/classes/_User/5DeGfe43PC. This break all the logic because try to update a existent user, I tried to fix the code, but always show more issues because session or auth (the session check is before the logic with the login, needs a big refactor there). Looking in the code I found that there is no place to update a logged third party user, is always create.

I did a test and a fix to this, but the issue with the session is a trouble. I don't know how is the response of parse to fix this (because this problem do not happens with client using parser official server).

Here the test of the issue: 0f3116e

@flovilmart
Copy link
Contributor

@weengo you haven't put the options --facebookAppIds when you launch the server

@Scoup the you do a put to the user you want to add the Facebook authData to the user you're modifying. If you enable anonymous users, you will ever be in that situation. The session check logic makes sense, we don't want anyone to modify you anonymous user. The logic to update a 3rd party logged in user is in RestWrite.js.

I'll try to reproduce the issue

@Scoup
Copy link

Scoup commented Mar 11, 2016

@flovilmart, I understand the session check, but I don't know all the flow when this happens. Because the client is trying to update a anonymous user, the server know that he already have another user, so after this "change" happens the client need to know. I think the server need to send back to client the new objectId and the new Session (because the old one is linked to the anonymous user).
But the session is created before you check third party user: https://github.com/ParsePlatform/parse-server/blob/master/src/RestWrite.js#L388 (so the session is always created to the anonymous user). And there is no way to call it again. And I'm now sure what is this conditions "!this.query" means, I'm trying to understand it.

Here is another problem: https://github.com/ParsePlatform/parse-server/blob/master/src/RestWrite.js#L223, because, if you see the data of my last post, the client send the facebook provider but sends the anonymous provider (objectId). I'm not sure if this should be fixed in client or the server needs to be aware about that.

Then, even if we change the code to let the flow until handleOAuthAuthData, still have the problem of not find the user before save. https://github.com/ParsePlatform/parse-server/blob/master/src/RestWrite.js#L346. And here there is no new session to send to user (since the last one is for the anonymous). So, I'm not sure about all this flow (I started to work in this code yesterday and my lack of understanding of flow could let me do mistakes). But I'm still trying to work on.

@flovilmart
Copy link
Contributor

@Scoup I've commented on the commit you provided as I'm not sure what you're trying to achieve.
I've worked on a fix for linking with multiple providers here b09a388
This is somewhat related to your issue I believe.

Going back to your issue:

The objectId is sent because the user exists (anonymous). Then it's try to do a PUT in /parse/classes/_User/5DeGfe43PC. This break all the logic because try to update a existent user,

This doesn't break the logic, it makes total sense. What's happening when you're doing a PUT is modify the current user with new information, in that case, Facebook authData. The flow then should be as following:

  1. Validate that the facebook.access_token is OK
  2. Find users that have the authData.facebook.id
    • if no users found -> this login info was never used before.
    • if 1 user is found, make sure the id match the passed objectId through the PUT otherwise throw an error as you're trying to use login information that is used by someone else.

@rafapetter
Copy link
Author

@flovilmart ok it's working now. It creates the user on first time log in, and just update when the user tries to login later.

This is the return data

"authData": {
        "facebook": {
            "access_token": "xxxxxxxxx",
            "expiration_date": "2016-05-09T16:37:57.678Z",
            "id": "xxxx"
        }
    },

And the authData is now being saved on mongodb

"_auth_data_facebook": {
        "access_token": "xxxxxx",
        "expiration_date": "2016-05-09T16:37:57.678Z",
        "id": "xxxxx"
    }

Ok, one last question so I can do more testing locally, how can I set on config.json to load the cloud files? I'm trying like this but it's not working: "cloud": "./cloud/main.js"

@flovilmart
Copy link
Contributor

Try to pass the full path to your CloudCode relative paths are kinda a pain... I may propose a fix for that for the path relative to your configuration file.

@Scoup
Copy link

Scoup commented Mar 11, 2016

@flovilmart, I think this is the problem related: parse-community/Parse-SDK-Android#350. As you can see, how they describe is exactly what my tests tries to show. And they say that the same code works with official parse.

There is another issues with android and anonymous user, that can be related, like this one, but I'm not sure: parse-community/Parse-SDK-Android#401

@flovilmart
Copy link
Contributor

After looking at the logs, this should be fixed by the PR just referenced here.
If you can test with the branch flovilmart.OAuthImprovements and confirm the error don't appear anymore.

@rafapetter
Copy link
Author

I'm testing again with enableAutomaticUser set to true on client. And now the _auth_data_facebook is not being saved back on mongodb, and therefore is back to creating new user every time. I've re-checked the code again to see if I've done something different, but for now I can only assume is the enableAutomaticUser.

@flovilmart
Copy link
Contributor

@weengo did you update to 2.1.6?

@rafapetter
Copy link
Author

yep, still the same issue

@rafapetter
Copy link
Author

I've now tried on aws, also with the 2.1.6 updated version, and it worked.

@flovilmart
Copy link
Contributor

are you sure your local npm is not linked with npm link, I recall we tried that at one point.

@rafapetter
Copy link
Author

It might be that then. I'm gonna reset locally and try again

@rafapetter
Copy link
Author

yep, my bad, I was still on branch flovilmart.OAuthImprovements, have moved back to master and all is fine now

@arpit529
Copy link

@weengo did you anything different in index.js to allow new Facebook user to login.

i have iOS app which use Facebook login to sign up. But new user cannot sign up also old users that i had on parse can login after moving to heroku parse server.

i would really appreciate the help.

@rafapetter
Copy link
Author

Hi @arpit529, nothing different, did you set your fb id on facebookAppIds: ['xxxxxx'] ? To be of a better help, you may want to post your index.js code here, covering your sensitive data.

I'm also running on an iOS app. Sign up and login are working, but there's one exception I've found: before the migration, I had an user with both username/password login and facebook linked, later this user have decided to unlink the facebook and only keep the username/password login. So, after the migration this user wasn't able to login again. To correct that I had to remove the column "facebook": null from the_User collection on mongodb.

I'd recommend you run your app again with VERBOSE=1, and post here the errors that you've found.

@flovilmart
Copy link
Contributor

where was that column facebook: null ? was it _auth_data_facebook ?

@rafapetter
Copy link
Author

On _User collection. Yes, I think was something like this.

"_auth_data_facebook": {
"facebook": null
}

Can't reproduce again because I've already past migration.

@flovilmart
Copy link
Contributor

ok, I'm looking into it

@arpit529
Copy link

@weengo Thanks for quick response.
Also are you seeing a issue where user is logged out if the app is killed in the background?
Revocable session doesn't seem to work after migration.

_index.js_********
// Example express application adding the parse-server module to expose Parse
// compatible API routes.

var express = require('express');
var ParseServer = require('parse-server').ParseServer;

var databaseUri = process.env.DATABASE_URI || process.env.MONGOLAB_URI;

if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}

var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://localhost:27017/dev',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'myAppId',
masterKey: process.env.MASTER_KEY || '', //Add your master key here. Keep it secret!
serverURL: process.env.SERVER_URL || 'http://localhost:1337' // Don't forget to change to https if needed
facebookAppIds: process.env.FACEBOOK_APP_ID,
});
// Client-keys like the javascript key or the .NET key are not necessary with parse-server
// If you wish you require them, you can set them as options in the initialization above:
// javascriptKey, restAPIKey, dotNetKey, clientKey

var app = express();

// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);

// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('I dream of being a web site.');
});

var port = process.env.PORT || 1337;
app.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});

@rafapetter
Copy link
Author

@arpit529, index looks ok. Could you run your app on VERBOSE=1 and send us the log? Would be better to see how the server and your app are communicating.

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

Successfully merging a pull request may close this issue.

7 participants