Search code examples
iosfacebookparse-platform

iOS Parse Facebook Login error 308 FBSDKLoginBadChallengeString


I'm trying to implement Facebook login in my iOS app, using Parse.

let permissionsArray = ["public_profile", "email"]

PFFacebookUtils.logInInBackgroundWithReadPermissions(permissionsArray)
    { (user: PFUser?, error: NSError?) in

    if let user = user {
        //we logged in!
    }
    else {
        //login error!
    }
}

This works well in the Simulator, but not on the device. On the device, I get this error:

Error Domain=com.facebook.sdk.login Code=308 "The operation couldn’t be completed. (com.facebook.sdk.login error 308.)

Error code 308 is for FBSDKLoginBadChallengeString, "The login response was missing a valid challenge string."

After I authorise my app on Facebook, this gets called:

func application(application: UIApplication, openURL url: NSURL, sourceApplication: String?, annotation: AnyObject?) -> Bool {
    return FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
}

The url is:

fb1640722449492705://authorize/#state=%7B%22challenge%22%3A%225OKWv3wN%2BEH%2BeQu48Xv6ty%2BRuek%3D%22%2C%22com.facebook.sdk_client_state%22%3Atrue%2C%223_method%22%3A1%2C%220_auth_logger_id%22%3A%22564CD915-2CFC-4989-9AF6-CEA389908D51%22%7D&granted_scopes=user_birthday%2Cpublic_profile&denied_scopes=&signed_request=c8SBBDeaNpF-R_XTYx4LRA0BWm5p9IwXDr8M4nL3YXI.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImNvZGUiOiJBUURhTXJibGw4Q3dITkd5M0xnQmNkVTNuYWRkeEVoTU5mMmx3eFpZU2IwZl9SU284YXhZdXZaRS02RnA2bU5Cdy1CWkVoRmt2Zk1xX1AxSHltUG00aWhkWE9hYmlvWFBiMnpCYkVnR1RRX3lzZVFIZXdHU19OcmpkNUF6WGtob1dfVE4wTmRrSGk5MzY0V2hFWUJDV0dfcE16RXpQVExHWE13X1dzb0QzZGtITm5fM0tHNjFxUjJyM3RDWVlNQTE4WENpS1dXTHUyM2dIRVhmTXc3ZTQ0M2xDQUtGRl9KSXcyVk1sS01FOTQ4dHQ2U1Fqb0tlVkp4RmJNSEFsWDZFYWxlUnQ2aGRrTGZlU2xuVTV5VjZ1bFhldHkxeEV5RmRDZVFHb2RXQ0dULVVCd3QyM0haY0dxNk8zbnE1cDRNWjNFZ012U2JhSGZyMmF6Wm8xUXk2X2xSQVNWcFlMVDZUdU5wZnMwVkJqNEdSaFEiLCJpc3N1ZWRfYXQiOjE0MzM0MTg2MDksInVzZXJfaWQiOiIxNDM3MzM0ODk5OTIwNDA5In0&access_token=CAAXUOnbG6uEBANtAd9DzWBSu4LLOEcPsu86Ny0Ir

Yes, I followed everything in Parse's Facebook login guide (made sure that all bundle IDs match, implemented all required AppDelegate methods, etc).

What exactly does this error mean and how do you solve it?


Solution

  • Fixed it. This issue was caused by logging in with Parse and with FBSDKLoginButton.

    Here's what I was doing:

    //in my UI setup code:
    let fbLoginButton = FBSDKLoginButton()
    fbLoginButton.addTarget(self, action: "fbButtonTouched:", forControlEvents: UIControlEvents.TouchUpInside)
    
    ....
    
    func fbButtonTouched() {
        let permissionsArray = ["public_profile", "email"]
    
        PFFacebookUtils.logInInBackgroundWithReadPermissions(permissionsArray)
            { (user: PFUser?, error: NSError?) in
    
                if let user = user {
                    //we logged in!
                }
                else {
                    //login error!
                }
        }
    }
    

    I found out (the hard way) that tapping a FBSDKLoginButton attempts to log the user in! There was no need to also log the user in using PFFacebookUtils.logInInBackgroundWithReadPermissions. So I just got rid of fbButtonTouched() and I could happily log in.

    So what happened was that I was attempting two logins at the same time, which the simulator was happy with, but not the device.

    If you want to know why, it's because the login authentication challenge it received did not correspond to the one it was expecting because it received the one from the first log in attempt after it had sent the one from the second log in attempt and was therefore waiting for the second log in attempts' authentication challenge.

    The documentation for FBSDKLoginButton doesn't currently mention anything about the fact that tapping it initiates the log in flow, and because it's a subclass of UIButton, you'd think that you ought to addTarget to it and implement the login flow yourself. And having two logins at the same time leads to a misleading FBSDKLoginBadChallengeString. Recipe for disaster...

    EDIT: The documentation has been updated correspondingly:

    FBSDKLoginButton works with [FBSDKAccessToken currentAccessToken] to determine what to display, and automatically starts authentication when tapped (i.e., you do not need to manually subscribe action targets).

    (my emphasis)