Top level redirect at client side Facebook Canvas / X-Frame-Options Deny - facebook

I am trying to build Facebook Canvas application using Java/Spring Social Facebook library.
When an user first time access the Canvas page(apps.facebook.com/mycanvasapp), facebook is doing HTTP POST with 'signed_request' in the body to my app url.
As the user is first time accessing the app, facebook sends empty 'oauth_token' in the POST body; hence my app returns HTTP 200 code with below Java Script code to present authorization dialog box to the user.
top.location.href='https://www.facebook.com/v2.5/dialog/oauth?client_id=12345&redirect_uri=https://myapp.com/canvas/';
This is to do top level redirect at client/browser side as HTTP server redirect is not allowed in iframe.
However, I do get below error in browser/Chrome logs and fails to present the authorization window to the user.
Refused to display 'https://myapp.com/canvas/' in a frame because it
set 'X-Frame-Options' to 'DENY'.
Similar question asked in other post -
Web App in Facebook Canvas / X-Frame-Options Deny Case
where it suggested to do browser side top level redirect instead of HTTP server redirect.
I am doing top level browser redirect only using 'top.location.href' in Java Script, but still experiencing same problem.
When i replay the request in the curl/command line, here is the response that my app is returning that seems to be okay to me.
HTTP/1.1 200 OK
Connection: keep-alive
Server: Apache-Coyote/1.1
X-Content-Type-Options: nosniff
X-Xss-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS, DELETE
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, X-Auth-Token
Content-Language: en-US
Transfer-Encoding: chunked
Date: Sat, 09 Jul 2016 04:40:17 GMT
Via: 1.1 vegur
<script>top.location.href='https://www.facebook.com/v2.5/dialog/oauth?client_id=12345&redirect_uri=https://myapp.com/canvas/';</script>
Tweaking 'X-Frame-Options' header field seems not helping much.
What am I missing ? Can some one please suggest a workable solution ?
There are some suggestions on using Facebook Java Script SDK library. But as my app contains within Facebook Canvas page, upon accessing the Canvas page Facebook does HTTP Post to my server, so wondering how to load HTML/Java Script to load Facebook Java Script SDK library before this process kicks in.
PS: I am using org.springframework.social.facebook.web.CanvasSignInController Spring pre-built controller in my app.

I resolved this problem by disabling/suppressing be security headers for the POST response from my server,
X-Content-Type-Options: nosniff X-Xss-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
X-Frame-Options: DENY Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, PUT, OPTIONS, DELETE
Access-Control-Max-Age: 3600 Access-Control-Allow-Headers: Origin,
X-Requested-With, Content-Type, Accept, X-
The key is to exclude X-Frame-Options & Strict-Transport-Security in the headers, that resolved the problem for me now.

Related

Graph API 2.3: <id>/Likes Requires Read_Stream?

I want users to like certain posts they are looking that. To do that I call <id>/likes as a POST-method.
The user has these permissions: basic_info, public_profile, publish_actions, read_custom_friendlists, user_friends, user_photos, user_posts
I load the posts using /feed/me, which should mean that Facebook will find those posts using their ids in subsequent calls.
The traffic to likes looks like this:
POST /v2.3/123456789012345_987654321098765/likes HTTP/1.1
Accept-Encoding: gzip
Authorization: Bearer blahblah...
User-Agent: Google-HTTP-Java-Client/1.11.0-beta (gzip)
Content-Length: 0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: graph.facebook.com
Connection: Keep-Alive
HTTP/1.1 400 Bad Request
Content-Type: text/javascript; charset=UTF-8
WWW-Authenticate: OAuth "Facebook Platform" "invalid_request" "(#100) Error finding the requested story"
Access-Control-Allow-Origin: *
X-FB-Rev: 1694181
Pragma: no-cache
Cache-Control: no-store
Facebook-API-Version: v2.3
Expires: Sat, 01 Jan 2000 00:00:00 GMT
X-FB-Debug: Ttvq+Mie2nN3jFdxREVlQj9pbZKanHPBUdlgNnOicrpDtOvEsrPOtoaKuQ+3w7TcG2L4lbWOLKhuDh4Zm14jlw==
Date: Fri, 17 Apr 2015 07:55:08 GMT
Connection: keep-alive
Content-Length: 99
{"error":{"message":"(#100) Error finding the requested story","type":"OAuthException","code":100}}"
I tried to make it work with Graph API Explorer. I added permission user_likes, but that didn't make it work. I added permission read_stream and suddenly it worked!
However, according to the documentation the user only needs publish_actions to like a post.
As we won't get read_stream we are stuck with what the documentation offers. Is this a bug or do we need other permissions or a different logic to make it work?
This was fixed by Facebook. Note however, that publish_actions alone won't do it for the various types of posts. E.g. if you want to like videos the user also must have the user_videos permission even though you don't want to play them.
On a further note, Facebook obviously does NOT use SO for technical things.

Logging in and Logging out in Perl

I have a Perl script which Logs in the user. After the user logs out, I am able to go back to the login page by pressing the back button. How can I prevent the user from doing so. The user should be prompted to login again after logging out. Also, after logging in when I press the back button the page redirects me to the login where logging in again should be mandatory.
In short the user should not be able to access the protected pages unless he authorizes.
A JavaScript solution from http://jakub.fedyczak.net/post/force-page-refresh-on-back-button/:
Put <body onunload=""> in your HTML output
Headers to set, as suggested by Quora's Adam D'Angelo:
Cache-Control: private, no-store, max-age=0, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Expires: Fri, 01 Jan 1990 00:00:00 GMT
In general,you should have some logic on the page that checks if the session is active/present and perform either a redirect (302, 307, etc...) that will send it to a login/authentication page, or a forbidden/authentication error (403, 401, etc...). That in addition to what #mob mentioned already, which will cause the browser to expire its local cache for that page.

If I enable migrations "July 2013 Breaking Changes" of my app, then search user by email wouldn't work

I'm using the search graph API to search for users by email. Here's an example of how I do that:
GET https://graph.facebook.com/search?q=Sample%40gmail.com&fields=name%2clink%2ceducation%2cid%2cwork%2cabout%2cpicture&limit=2&type=user&access_token=...
Before the July 2013 Breaking Changes it was working fine. Once I enabled the breaking changes I start getting HTTP 403 saying that that the access token is not valid.
HTTP/1.1 403 Forbidden
Access-Control-Allow-Origin: *
Cache-Control: no-store
Content-Type: text/javascript; charset=UTF-8
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Pragma: no-cache
WWW-Authenticate: OAuth "Facebook Platform" "insufficient_scope" "(#200) Must have a valid access_token to access this endpoint"
X-FB-Rev: 798183
X-FB-Debug: lZPVbdTmZrCo+Bde/MNEXy/halUzQx7qIDW5aiZeT0g=
Date: Mon, 29 Apr 2013 07:25:29 GMT
Connection: keep-alive
Content-Length: 120
{"error":{"message":"(#200) Must have a valid access_token to access this endpoint","type":"OAuthException","code":200}}
Once I remove the %40 (# sign) or the '.com' part from the request I get a normal HTTP 200 results. The problem is, that it's not what I'm looking for. I want to be able to search for users by email the way I was able before.
Example of requests that does work:
GET https://graph.facebook.com/search?q=Samplegmail.com&fields=name%2clink%2ceducation%2cid%2cwork%2cabout%2cpicture&limit=2&type=user&access_token=...
GET https://graph.facebook.com/search?q=Sample%40gmail&fields=name%2clink%2ceducation%2cid%2cwork%2cabout%2cpicture&limit=2&type=user&access_token=...
As 林果皞 said. This is a bug in the graph API. I filed a bug here:
https://developers.facebook.com/bugs/335452696581712
have you try FQL?
SELECT uid,username,first_name, middle_name, pic,pic_small, pic_big,
pic_square,
last_name,name,email,birthday,birthday_date,contact_email,current_address,current_location,education,hometown_location,
languages, locale,profile_url,sex,work FROM user where
contains('youremail#example.com')
Search by email works fine to me (Access token just granted basic permissions enough):
https://developers.facebook.com/tools/explorer?method=GET&path=%2Fsearch%3Fq%3Dlimkokhole%40gmail.com%26fields%3Dname%2Clink%2Ceducation%2Cid%2Cwork%2Cabout%2Cpicture%26limit%3D2%26type%3Duser
Update:
Recently Graph API explorer app already enabled "July 2013 Breaking
Changes". So the example i've shown above whouldn't work anymore.

Facebook oauth redirect does not work in iframe

Recently I noticed that my applications on Facebook stopped to work properly.
When someone opens app who did not authorize in yet I display simple content with link,
When link is clicked, in application I issue redirect (in Spring I return "redirect:...url..") to URL:
https://www.facebook.com/dialog/oauth?scope=email&client_id=317651918315301&redirect_uri=https%3A%2F%2Fapps.facebook.com%2Facnestop&scope=email&response_type=token
it sends 302 with given location to iFrame.
Then blank iFrame is displayed, and following headers from FB are returned:
Cache-Control private, no-cache, no-store, must-revalidate
Connection keep-alive
Content-Encoding gzip
Content-Type text/html; charset=utf-8
Date Fri, 25 May 2012 10:37:11 GMT
Expires Sat, 01 Jan 2000 00:00:00 GMT
P3P CP="Facebook does not have a P3P policy. Learn why here: http://fb.me/p3p"
Pragma no-cache
Set-Cookie _e_1vFX_0=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.facebook.com; httponly locale=pl_PL; expires=Fri, 01-Jun-2012 10:37:11 GMT; path=/; domain=.facebook.com wd=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.facebook.com; httponly
Transfer-Encoding chunked
X-Content-Type-Options nosniff
X-FB-Debug VYI+cCm/Vfpx3US82n06uFuw5gF6UQDg+8GUSpGUL9A=
X-Frame-Options DENY
X-XSS-Protection 0
x-content-security-policy... allow *;script-src https://*.facebook.com http://*.facebook.com https://*.fbcdn.net http://*.fbcdn.net *.facebook.net *.google-analytics.com *.virtualearth.net *.google.com 127.0.0.1:* *.spotilocal.com:*;options inline-script eval-script;report-uri https://www.facebook.com/csp.php
And just blank iFrame is displayed.
When URL which I redirect to is pasted to browser directly - it displays Facebook prompt to authorise app.
Any ideas why behavior is different when iFrame is redirected from pasting and opening same link in browser?
I noticed this today, previously app was working fine.
This is my sample app:
https://apps.facebook.com/acnestop/
If the user has not authorized your application, you need not handle that, facebook takes care of that.
But handling the case where a user has not logged in you can use getLoginURL
$loginUrl = $facebook->getLoginUrl(
array(
'scope' => 'email,user_checkins,etc',
'redirect_uri' => 'https://apps.facebook.com/my-application/'
)
);
Do not forget the trailing slash in redirect_uri
Hope this helps
Taken from Facebook:
Because your game is loaded in an iframe, returning a 302 to redirect the user to the Login >Dialog will be unsuccessful. Instead you must target the top (or _top) frame for redirect, >which causes the parent window to redirect to the Login Dialog URL.
Thus, you must redirect the user manually to something like
https://www.facebook.com/dialog/oauth?client_id=YOURID&redirect_uri=YOUR-REDIRECT-URI
It's because Facebook 0auth don't support iframe anymore.
U can see that in response header x-iframe-options:deny

Facebook status.get API throws 500 HTTP status code

I have an APP that calls Facebook status.get method via the REST server - restserver.php using session key method. This app works fine for most of the users, but for one user I consistently receive HTTP 500 status code. Since this doesn't have any specific Facebook error message, it is almost impossible for me to debug this.
Anyone faced a similar problem? What could be wrong with this user account? I checked the privacy options that I could think of and they look fine.
Also, for the same user, I can use friends.get method without any problem.
EDIT: I tried in Facebook forums as well, but it was of no use. Any pointers in the direction towards debugging/troubleshooting this problem are also appreciated.
EDIT: The full HTTP trace of my request is as follows. Just to be clear the same code works for other users.
REQUEST
=======================
GET /restserver.php?method=facebook.status.get&limit=1&api_key=a134957738cbd097e76bcefee86c75db&v=1.0&call_id=8cc99cec1562a71&format=JSON&session_key=747ad19e9859993f97c20355-1038949180&sig=5f597e80ad081b30c7155e9176a2aa04 HTTP/1.1
User-Agent: Pandemonium
Content-Type: application/x-www-form-urlencoded
Host: api.facebook.com
RESPONSE
=======================
HTTP/1.1 500 Internal Server Error
Cache-Control: private, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-type: application/json
Expires: Sat, 01 Jan 2000 00:00:00 GMT
P3P: CP="DSP LAW"
Pragma: no-cache
Set-Cookie: datr=1269479340-0545d70990e5f2db3b59176d82435f687f48a4bc69b5f11be9364; expires=Sat, 24-Mar-2012 01:09:00 GMT; path=/; domain=.facebook.com
X-Cnection: close
Date: Thu, 25 Mar 2010 01:09:32 GMT
Content-Length: 0
I had the same problem and just added the description field to my API call. When I deleted the description from my fields the server error was fixed. No idea why it can't handle the description field.
$events = $this->facebook->api('/me/events?fields=name,venue,privacy,location');
The user had already approved the status.get permissions?