Having problems getting the Facebook v4 iOS plugin to login, possibly due to ATS

I recently updated my copy of Xcode, and with that came the glorious App Transport Security changes.  

I fixed those by updating my plist file accordingly, and then decided I would update the Facebook plugin in my app so that it used the v4 plugin (I’d been putting it off for a while).

As far as I can tell I’ve updated everything correctly as per the migration guide. However when I try to call facebook.login, it switches to the FB app as expected, but then when it comes back to my app the Facebook listener receives the following event:

table: 0x1dcf7560 { [type] =\> "session" [name] =\> "fbconnect" [phase] =\> "loginCancelled" [isError] =\> false [response] =\> "" }

I don’t get receive other events in the listener at all, just the cancelled one. Other than clicking the button in my game which triggers the login call, I haven’t touched anything else on screen so I’m definitely not hitting a cancel button.  

In addition, this is an app that I have already signed into FB with,so it doesn’t even show me the “do you want to allow this app to sign in” page. It just goes to Facebook and then straight back to my app with no interaction on my part, and then says the login was cancelled.  

The whole process takes maybe…5 seconds so I don’t think it’s timing out.

I’m fairly sure related to ATS, but as far as I can tell should not be happening due to my plist settings. When the login call is made I see this in my console:

error: "This app is not allowed to query for scheme fbXXXXXXXXXXXXXX"

where fbXXXXXXXXXXXXXX is my facebook app ID.  

I already have “fbXXXXXXXXXXXXXX” in my plist’s LSApplicationQueriesSchemes array, and in NSAppTransportSecurity->NSExceptionDomains I also have facebook.com, graph.facebook.com, fbcdn.net and akamaihd.net

All fields also have the following keys:

\<key\>NSIncludesSubdomains\</key\> \<true/\> \<key\>NSExceptionAllowsInsecureHTTPLoads\</key\> \<true/\> \<key\>NSExceptionRequiresForwardSecrecy\</key\> \<false/\>

What else could be needed in order to get this to work correctly?

Hi Alan QuizTix,

It looks like Facebook’s iOS 9 docs may have changed since the Facebook-v4 docs were originally written. According to those docs now, you should use the key NSThirdPartyExceptionRequiresForwardSecrecy.

Also, in your LSApplicationQueriesSchemes array, make sure you’ve added the following:

\<key\>LSApplicationQueriesSchemes\</key\> \<array\> \<string\>fbapi\</string\> \<string\>fbapi20130214\</string\> \<string\>fbapi20130410\</string\> \<string\>fbapi20130702\</string\> \<string\>fbapi20131010\</string\> \<string\>fbapi20131219\</string\> \<string\>fbapi20140410\</string\> \<string\>fbapi20140116\</string\> \<string\>fbapi20150313\</string\> \<string\>fbapi20150629\</string\> \<string\>fbauth\</string\> \<string\>fbauth2\</string\> \<string\>fb-messenger-api20140430\</string\> \</array\>

The Facebook-v4 plugin currently targets v4.5.0 of the Facebook SDK, so there’s a larger amount of content needed in the LSApplicationQueriesSchemes array.

Hope that helps.

I’ve just tried using NSThirdPartyExceptionRequiresForwardSecrecy and NSThirdPartyExceptionAllowsInsecureHTTPLoads but I’m still getting the same response.

I already have those strings in my LSApplicationQueriesSchemes array as well, plus the one I mentioned earlier (fbMYAPPID).

I’m really not sure what else could be causing the problem.

Edit: if this is any use, I’ve added a launch url listener to the app so I can see what is being used to reopen the app in order to return from Facebook:

fbMYAPPID://authorize#e2e=%7B%22init%22%3A1453806352933%7D&expires\_in=5101638&signed\_request=LOTS\_OF\_JUMBLED\_CHARACTERS&state=%7B%22challenge%22%3A%22Div1PAL3mwpLlxUY2e0AWPRuklk%3D%22%2C%22com.facebook.sdk\_client\_state%22%3Atrue%2C%223\_method%22%3A0%2C%220\_auth\_logger\_id%22%3A%224XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX%22%7D&granted\_scopes=user\_friends%2Cemail%2Ccontact\_email%2Cpublish\_actions%2Cpublic\_profile&denied\_scopes=&access\_token=LOTS\_OF\_JUMBLED\_CHARACTERS

I’ve masked the actual tokens etc, but it looks to me like a valid response has come back. It has an access token, it also shows some granted permissions, and the denied_scopes field is empty. The expires_in time is approx 60 days.

Did you add the CoronaDelegates key to your Info.plist as well?

\<key\>CoronaDelegates\</key\> \<array\> \<string\>CoronaFacebookDelegate\</string\> \</array\>

It’s needed to get login working, but our documentation could highlight this a little better than it currently does.

Yes I had already added the CoronaDelegates key.

Hi Alan QuizTix,

After casually browsing through the Changelog for the iOS Facebook SDK, I came across this note for SDK 4.9.0,

“Fixed login bug that treated a request for no new permissions as a cancellation.”

The iOS version of Facebook-v4 uses Facebook SDK 4.5.1, so it may be worth testing to see if you’re hitting this bug. You can do this by adding some arbitrary facebook permission to your facebook.login() call.

Thank you, I’l test this out today. I am making a permission-less request, so it’s quite possible this is the cause.

I tried requesting the “public_profile” permission, and that didn’t work.  

I realise it’s granted by default, but if the only way to get login to work is to request a new permission every time, then surely that will violate FB’s T&Cs about requesting unneeded permissions (or requesting them before they are needed)?

Is this issue also affecting everyone else who is using the plugin, or have I overlooked something?

Hmm. Internally, the “public_profile” permission and “user_friends” permissions are always included when facebook.login() occurs.

I guess the thing to test to confirm the issue entirely would be to add a permission like “email” to your facebook.login() call and see if that succeeds. Then logout, restart the app, then login again with the same facebook.login() call as before. Assuming that the second call fails, then it sounds like this is in fact the bug you’re encountering.

As it turns out, I’d already tested with a non-default permission “user_games_activity” (at least I don’t think it’s accepted by default), and that hadn’t worked. Just tried with “email” and the same thing happened.  

I’ve also just tested with App Transport Security Settings->Allow Arbitrary Loads set to true, just in case there was a request being blocked by ATS. Same thing, it all appears like it’s working but then the listener only receives a “loginCancelled” phase.

If it’s any help, I’m using Xcode 7.2 and Corona Enterprise build 2015.2743 - presumably there is nothing about those builds in particular that should be causing this issue? I could test with a newer Enterprise build, but I’m always reluctant in case something else has been changed in the meantime that I rely on (e.g. when storyboard was deprecated - an easy fix but easy to overlook until you need to update it).

I put this on the back burner while I looked at some Android stuff that I needed to do, and have come back to it today.  

I’ve just updated Corona to the latest daily build 2016.2830 and tried again (I also grabbed the FB-v4 lib again in case it had been updated). I’m still getting the exact same error. As I said in my original posts, the URL used by FB to return to my app makes it seem as though everything is being sent back correctly, but then it always triggers the “cancelled” phase. I’ve also tried using a brand new Facebook account, just to see if that made any difference (it didn’t).

Has nobody else ran into this problem? I’m pulling my hair out trying to work out why this is happening.

I’ve seen this right now as I’ve faced -probably- a similar (or same) issue.

I’m having problems when I try to post a link with Facebook v4 integration.

It opens up the Facebook interface for authorization and after that when I try to post the link, it says “the link may be harmful. please enter captcha code” (something like that).

The user enters the code successfully and the share interface with everything I want. The link, image, score of player.

When I press “Share”, Facebook redirects me to the Login page saying “you have to log in first” even though I’m logged in and gave the appropriate permissions to the app.

I don’t think it matters but I’m using daily build 2016.2870.

Hi Alan QuizTix,

It looks like Facebook’s iOS 9 docs may have changed since the Facebook-v4 docs were originally written. According to those docs now, you should use the key NSThirdPartyExceptionRequiresForwardSecrecy.

Also, in your LSApplicationQueriesSchemes array, make sure you’ve added the following:

\<key\>LSApplicationQueriesSchemes\</key\> \<array\> \<string\>fbapi\</string\> \<string\>fbapi20130214\</string\> \<string\>fbapi20130410\</string\> \<string\>fbapi20130702\</string\> \<string\>fbapi20131010\</string\> \<string\>fbapi20131219\</string\> \<string\>fbapi20140410\</string\> \<string\>fbapi20140116\</string\> \<string\>fbapi20150313\</string\> \<string\>fbapi20150629\</string\> \<string\>fbauth\</string\> \<string\>fbauth2\</string\> \<string\>fb-messenger-api20140430\</string\> \</array\>

The Facebook-v4 plugin currently targets v4.5.0 of the Facebook SDK, so there’s a larger amount of content needed in the LSApplicationQueriesSchemes array.

Hope that helps.

I’ve just tried using NSThirdPartyExceptionRequiresForwardSecrecy and NSThirdPartyExceptionAllowsInsecureHTTPLoads but I’m still getting the same response.

I already have those strings in my LSApplicationQueriesSchemes array as well, plus the one I mentioned earlier (fbMYAPPID).

I’m really not sure what else could be causing the problem.

Edit: if this is any use, I’ve added a launch url listener to the app so I can see what is being used to reopen the app in order to return from Facebook:

fbMYAPPID://authorize#e2e=%7B%22init%22%3A1453806352933%7D&expires\_in=5101638&signed\_request=LOTS\_OF\_JUMBLED\_CHARACTERS&state=%7B%22challenge%22%3A%22Div1PAL3mwpLlxUY2e0AWPRuklk%3D%22%2C%22com.facebook.sdk\_client\_state%22%3Atrue%2C%223\_method%22%3A0%2C%220\_auth\_logger\_id%22%3A%224XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX%22%7D&granted\_scopes=user\_friends%2Cemail%2Ccontact\_email%2Cpublish\_actions%2Cpublic\_profile&denied\_scopes=&access\_token=LOTS\_OF\_JUMBLED\_CHARACTERS

I’ve masked the actual tokens etc, but it looks to me like a valid response has come back. It has an access token, it also shows some granted permissions, and the denied_scopes field is empty. The expires_in time is approx 60 days.

Did you add the CoronaDelegates key to your Info.plist as well?

\<key\>CoronaDelegates\</key\> \<array\> \<string\>CoronaFacebookDelegate\</string\> \</array\>

It’s needed to get login working, but our documentation could highlight this a little better than it currently does.

Yes I had already added the CoronaDelegates key.

Hi Alan QuizTix,

After casually browsing through the Changelog for the iOS Facebook SDK, I came across this note for SDK 4.9.0,

“Fixed login bug that treated a request for no new permissions as a cancellation.”

The iOS version of Facebook-v4 uses Facebook SDK 4.5.1, so it may be worth testing to see if you’re hitting this bug. You can do this by adding some arbitrary facebook permission to your facebook.login() call.

Thank you, I’l test this out today. I am making a permission-less request, so it’s quite possible this is the cause.

I tried requesting the “public_profile” permission, and that didn’t work.  

I realise it’s granted by default, but if the only way to get login to work is to request a new permission every time, then surely that will violate FB’s T&Cs about requesting unneeded permissions (or requesting them before they are needed)?

Is this issue also affecting everyone else who is using the plugin, or have I overlooked something?

Hmm. Internally, the “public_profile” permission and “user_friends” permissions are always included when facebook.login() occurs.

I guess the thing to test to confirm the issue entirely would be to add a permission like “email” to your facebook.login() call and see if that succeeds. Then logout, restart the app, then login again with the same facebook.login() call as before. Assuming that the second call fails, then it sounds like this is in fact the bug you’re encountering.