parse-community / parse-server

Parse Server for Node.js / Express
https://parseplatform.org
Apache License 2.0
20.9k stars 4.78k forks source link

Login via Facebook fails with parse-server #1527

Closed kwstasna closed 8 years ago

kwstasna commented 8 years ago

Check out this issue for an ideal bug report. The closer your issue report is to that one, the more likely we are to be able to help, and the more likely we will be to fix the issue quickly!

For implementation related questions or technical support, please refer to the Stack Overflow and Server Fault communities.

Make sure these boxes are checked before submitting your issue -- thanks for reporting issues back to Parse Server!

Ubuntu 14.04 NodeJS v5.10.1 mongodb v3.0.11 Parse ios sdk 1.12 Parse-Server 2.2.7 Parse-Dashboard 1.0.9

Steps to reproduce

Hello. I 'm making one app with swift 2 and make it with facebook login. Normally in the parse.com version with appid and client key from the site it works perfect. But since i've been testing it with parse-server if always fails. And i cant figure out why.

This is my index.js file that i run it exactly as parse-server-example.

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

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

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

var api = new ParseServer({
  databaseURI: databaseUri || 'mongodb://localhost:27017/recDB',
  cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
  appId: process.env.APP_ID || 'APPID',
  masterKey: process.env.MASTER_KEY || 'MASTERKEY', //Add your master key here. Keep it secret!
  serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse',  // Don't forget to change to https if needed
  liveQuery: {
    classNames: ["Posts", "Comments"] // List of classes to support for query subscriptions
  },
  facebookAppIds: 'FACEBOOKID'
});
// 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 static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));

// 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('Make sure to star the parse-server repo on GitHub!');
});

// There will be a test page available on the /test path of your server url
// Remove this before launching your app
app.get('/test', function(req, res) {
  res.sendFile(path.join(__dirname, '/public/test.html'));
});

var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);

So when i try to login via facebook i have write this code that as soon as i get the permission i make a new _User and i save name email and image. Dont forget that the exact code works like a charm for parse.com

@IBAction func signInWithFB(sender: AnyObject) {
        let permissions = ["public_profile", "email"]        
        PFFacebookUtils.logInInBackgroundWithReadPermissions(permissions) { (user: PFUser?, error: NSError?) -> Void in
            if let error = error{                
                print(error)
            } else {                
                if let _ = user {               
                    let graphRequest = FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, email"])
                    graphRequest.startWithCompletionHandler({
                        (connection, result, error) -> Void in                        
                        if error != nil {
                            print(error)                          
                        } else if let result = result {                            
                           let optionalname = result["name"] as? String
                            let optionalmail = result["email"] as? String
                            let userId = result["id"] as! String
                            let userObj = PFUser.currentUser()
                            userObj!["email"] = optionalmail!
                            userObj![USER_FULLNAME] = optionalname!
                            let fbimg = "https://graph.facebook.com/" + userId + "/picture?type=large"
                            if let fbpicurl = NSURL(string: fbimg) {
                                if let data = NSData(contentsOfURL: fbpicurl){
                                    let imageFile = PFFile(name:"avatar.jpg", data:data)
                                    userObj![USER_AVATAR] = imageFile
                                    print(imageFile)
                                }
                            }
                     userObj!.saveInBackgroundWithBlock { (success, error) -> Void in
                                if error == nil {
                                    let alert = UIAlertView(title: APP_NAME,
                                        message: "Welcome to My APP!",
                                        delegate: nil,
                                        cancelButtonTitle: "OK" )
                                    alert.show()
                                    self.view.hideHUD()
                                    self.navigationController?.popViewControllerAnimated(true)                                   
                                } else {
                                    let alert = UIAlertView(title: APP_NAME,
                                        message: "\(error!.localizedDescription)",
                                        delegate: nil,
                                        cancelButtonTitle: "OK" )
                                    alert.show()
                                    self.view.hideHUD()
                                } }                                                      
                        }                        
                    })                 
                    self.dismissViewControllerAnimated(true, completion: nil)
                }
            }
        }     
    }

Logs/Trace

And i get this error

Optional(<PFFile: 0x7a71ae80>) 2016-04-17 13:33:47.275 Recipes[740:18763] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't use nil for keys or values on PFObject. Use NSNull for values.' * First throw call stack: ( 0 CoreFoundation 0x02219a14 exceptionPreprocess + 180 1 libobjc.A.dylib 0x042a3e02 objc_exception_throw + 50 2 CoreFoundation 0x0221993d +[NSException raise:format:] + 141 3 Recipes 0x00248be6 -[PFObject(Private) _setObject:forKey:onlyIfDifferent:] + 125 4 Recipes 0x0024cc30 -[PFObject setObject:forKey:] + 68 5 Recipes 0x002a7721 -[PFInstallation setObject:forKey:] + 454 6 Recipes 0x0024cc7c -[PFObject setObject:forKeyedSubscript:] + 60 7 Recipes 0x000e1e66 _TFC7Recipes7Account13viewDidAppearfS0FSbT + 1942 8 Recipes 0x000e2b3f _TToFC7Recipes7Account13viewDidAppearfS0FSbT + 63 9 UIKit 0x02fa5daa -[UIViewController _setViewAppearState:isAnimating:] + 774 10 UIKit 0x02fa6529 -[UIViewController viewDidAppear:] + 166 11 UIKit 0x02fe58d0 -[UINavigationController viewDidAppear:] + 227 12 UIKit 0x02fa5daa -[UIViewController _setViewAppearState:isAnimating:] + 774 13 UIKit 0x02fa6529 -[UIViewController __viewDidAppear:] + 166 14 UIKit 0x030031cc -[UITabBarController viewDidAppear:] + 129 15 UIKit 0x02fa5daa -[UIViewController _setViewAppearState:isAnimating:] + 774 16 UIKit 0x02fa6529 -[UIViewController viewDidAppear:] + 166 17 UIKit 0x02fa6802 -[UIViewController _endAppearanceTransition:] + 280 18 UIKit 0x02fc95ea -[UIViewController(UIContainerViewControllerProtectedMethods) endAppearanceTransition] + 41 19 UIKit 0x02f6a640 -[UIPresentationController transitionDidFinish:] + 939 20 UIKit 0x0317b8ec -[_UICurrentContextPresentationController transitionDidFinish:] + 56 21 UIKit 0x02f6e4be __56-[UIPresentationController runTransitionForCurrentState]_block_invoke_2 + 224 22 UIKit 0x0391c873 -[_UIViewControllerTransitionContext completeTransition:] + 118 23 UIKit 0x039470a1 -[UIViewControllerBuiltinTransitionViewAnimator transitionViewDidComplete:fromView:toView:removeFromView:] + 74 24 UIKit 0x02f66f5a -[UITransitionView notifyDidCompleteTransition:] + 280 25 UIKit 0x02f66c46 -[UITransitionView _didCompleteTransition:] + 1550 26 UIKit 0x02f69881 -[UITransitionView _transitionDidStop:finished:] + 121 27 UIKit 0x02e6dc53 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 247 28 UIKit 0x02e6e049 -[UIViewAnimationState animationDidStop:finished:] + 90 29 QuartzCore 0x0179c095 _ZN2CA5Layer23run_animation_callbacksEPv + 305 30 libdispatch.dylib 0x0524f9cd _dispatch_client_callout + 14 31 libdispatch.dylib 0x05234f90 _dispatch_main_queue_callback_4CF + 910 32 CoreFoundation 0x0216afde __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 14 33 CoreFoundation 0x02128cd4 __CFRunLoopRun + 2356 34 CoreFoundation 0x021280e6 CFRunLoopRunSpecific + 470 35 CoreFoundation 0x02127efb CFRunLoopRunInMode + 123 36 GraphicsServices 0x068c6664 GSEventRunModal + 192 37 GraphicsServices 0x068c64a1 GSEventRun + 104 38 UIKit 0x02dd3bfa UIApplicationMain + 160 39 Recipes 0x00125dac main + 140 40 libdyld.dylib 0x05279a21 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

So i go at my parse-server-dashboard and i can see that a user it is created. Sometimes it takes all the data "Name, email, image" but has no AuthData. At the "username" column it ALWAYS has something, i guess its the user id in facebook.

So does anyone have any idea? I dont know where to look for. Thank!

otymartin commented 8 years ago

Perhaps

facebookAppIds: 'FACEBOOKID' 

should be...

facebook: {
     appIds: "FACEBOOK APP ID"
   }

As referenced herein the official guide

EDIT: I tried this myself and it was failing while deploying to app engine. So I read that facebookAppIds: 'FACEBOOKID' is actually an array of AppId's.

Therefore this worked at deployment.

facebookAppIds: ['FACEBOOKID']

Working on integrating facebook login myself using your code so I will update if I see success

kwstasna commented 8 years ago

@otymartin still have the same error with the edit! Hope you find what is missing and thanks for your time! I'm trying to figoure out also but with no success.. as i said, sometimes it gets all the data "name, email, image" everytime it gets "username" the facebook id but never has taken the authData.

steven-supersolid commented 8 years ago

I can't actually see the facebookAppIds config value used in the auth code. The fact that a User is being created means that something is working.

Some things to check:

The username should be randomly generated for Facebook and Anonymous signup.

kwstasna commented 8 years ago

@samwgoldman 1) It's still the same. 2) Null EVERY time. Even if i get all the data "name, email, image" (sometimes i get them all), the authData is always null. 3) I have no idea how to check it but since authData is null i guess its this one. Because on parse.com version i get the authData normally and i can login!

steven-supersolid commented 8 years ago

It could be that authData is not returned to the client SDK when you log in, but are you saying the database field is completely empty too in the data browser or mongo shell?

I can't offer much help with the iOS SDK but have you tried not setting any custom fields on userObj and seeing if that saves? Potentially one of these fields is nil and that is what is causing the problem. If you can find out by commenting out code until it works (or uncommenting until it breaks) the problem may become obvious.

jdzorz commented 8 years ago

@kwstasna how does your app delegate look? i was having the same problem as well. i managed to get it working using the parseui - PFloginviewcontroller.

kwstasna commented 8 years ago

@jdzorz @otymartin @steven-supersolid Ok guys i found out the issue. So my app is doing the following steps. When the user logins successfully it goes from LoginView to AccountView. In the accountView in the func viewDidAppear i had 3 lines of code that registers the User to the Installation class so he can receive notifications.

            let installation = PFInstallation.currentInstallation()
            installation["user"] = PFUser.currentUser()!.username
            installation.saveInBackground()

This was nil and it threw the exception.

But when i go to the User's class i can actually see that the "username" column is NOT nil ! It has numbers and letters.

So as i told you before in parse.com version i have NO problem, it takes also the current user username and it puts it to the column "user" inside Installation class.

So the problem is this right now !

FYI this is the complete function

override func viewDidAppear(animated: Bool) {

        if PFUser.currentUser() == nil {
        noUserView.hidden = false
        mainView.hidden = true

    } else {

        noUserView.hidden = true
        mainView.hidden = false

        // Associate the device with a user for Push Notifications

            let installation = PFInstallation.currentInstallation()
             installation["user"] = PFUser.currentUser()!.username
            installation.saveInBackground()
//the three lines above cause problem in parse-server BUT NOT in parse.com

        // Call query for My recipes
        someQueries()
        showUserDetails()

    }
kwstasna commented 8 years ago

So what i did is to put the "id" of the Facebook User to the column "username" because each one have a unique username so i will have no conflict by users. And also now i have no exceptions no errors. Although i think this is something they have to look because the exactly the same code at parse.com works and at parse-server doesn't. Thanks all for your help!