Ability to pass through custom data on Omniauth-powered Facebook auth requests - facebook

Omniauth branch 0-3-stable of git://github.com/intridea/omniauth.git
Rails 3.0.7
When Omniauth redirects a user to the Facebook auth dialog by making a GET call to "/auth/facebook", if that user clicks "Cancel" from the auth dialog, then we can the callback request
GET "/auth/facebook/callback?error_reason=user_denied&error=access_denied&error_description=The+user+denied+your+request."
which Omniauth immediately appears to redirect to:
GET "/auth/failure?message=invalid_credentials"
Unfortunately, when this is a response to an app. invitation generated by the FB request dialog, there is no identifying information on which user has "Canceled" out of the auth dialog. If we could send along some identifying information with the Omniauth request, we could allow ourselves to "remember" which user did the "Canceling" which would help us track explicit denials on the back end.
Is there any way to send along data with the call to "/auth/facebook" that would simply get repeated back to us in the resulting call to "/auth/facebook/callback"? This would be similar to the "data" parameter in the requests dialog documentation.
Thanks,
Wes

You can pass through a 'state' param which will be passed along to the callback url.
eg. you'd make a call to '/auth/facebook?state=SOME_INFO'
Then in the controller action that you route '/auth/facebook/callback' to, you retrieve just as you would a normal param:
info = params[:state]
The param must be named 'state'. This is mentioned in the omniauth-facebook documentation under the section 'Per-Request Options'.
https://github.com/mkdynamic/omniauth-facebook

Related

hwiOAuthBundle error on getting picture from facebook

I'd configure a oAuth connection with the official documentation. All works except getting the profile picture from facebook.
The front redirects the valid user to a custom user-bundle register (need more data)
The weird part: When I try to use "infos_url" param, it redirects the autenticated user to the original register form, not the custom one. Either use the custom FOSUserProvider that gets the data.
any ideas?

pass data back to facebook app after authorisation

I am authotizing my app in the following way:
// authorize app!
$('#authApp').click(function(){
var oauth_url = 'https://www.facebook.com/dialog/oauth/';
oauth_url += '?client_id=#{app.id}';
oauth_url += '&redirect_uri=' + encodeURIComponent('https://www.facebook.com/pages/null/#{fbPageId()}/?sk=app_#{app.id}');
oauth_url += '&scope=user_likes,user_photos';
oauth_url += '&app_data=7B%27game%27%3A+%27key%27%7D';
oauth_url += '&state=sbSbsbSb';
As you can see I am setting the 'state' param as part of the query string.
Now when the user authorizes the app he is redirected to the redirect url.
However the data passed in the state parameter is not posted to my app nor is it part of my app's iframe query string. I was expecting to find it as part of the signed request, but no. This is the deserialized signed request posted back after authorisation
{ algorithm: 'HMAC-SHA256',
expires: 1348927200,
issued_at: 1348921162,
oauth_token: 'AAA...',
page: { id: '490...', liked: true, admin: false },
user: { country: 'ec', locale: 'en_US', age: { min: 21 } },
user_id: '1...' }
I do see that the state is included of the parent page's query string. I need to access that parameter from my app (running inside an iframe). I believe that I cannot just access the parent page's window location because of same origin policy restrictions.
I have read through the documentation and searched online. Persisting data across an app authotization needs to be done using the state parameter. However it is nowhere stated how to retrieve that state param once redirected back to your app.
This is from the facebook doc's regarding the state param:
A unique string used to maintain application state between the request
and callback. When Facebook redirects the user back to your
redirect_uri, this parameter's value will be included in the response.
You should use this to protect against Cross-Site Request Forgery.
Am I supposed to get the state data back from the parent's page query string?
Or am I doing something wrong?
* EDIT *
I am storing the user to user request Id in the state parameter. For example A invites B to participate in the app via a facebook request. Once B authorises the app A needs to be rewarded. So I need to know that B came to the app following A's invitation. Therefore I store the requestId in the state param, so once B has authorised the app I can take appropriate action.
* EDIT 2 (SOLUTION) **
If your redirect_uri is pointing to the Page Tab URL then facebook will NOT send back the state parameter! It will only be sent back if you redirect to the Canvas URL !!!!!
The Facebook documentation you referenced is a bit confusing. The only thing you should be doing with the state parameter is making sure you are not a victim of CSRF. Facebook's server side authentication flow gives an example of this in PHP. In short, you should be storing the state value in the session and then verifying that the session value is the same as what Facebook passes back to you in the request. The key line in their PHP example is:
if($_SESSION['state'] && ($_SESSION['state'] === $_REQUEST['state'])) {
// Continue with application logic here because state matches.
// Otherwise, exit immediately because you're a victim of CSRF!
So back to your problem. From your redirect URL and the response you are getting, it's obvious your app is on a Facebook Page Tab. See the authentication flow for page tabs for how you should be doing this. Note they are not using the state parameter in step 2 and that the state parameter is never mentioned in page tab authentication flow. So even if you wanted to use the state parameter for something other than its intended use, you are out of luck.
Based on your edits, I suggest you check out the documentation on requests. Note that the user clicking on the request will be redirected to your canvas app, not the page tab. "The canvas URL will also contain an additional GET parameter request_ids, which is a comma delimited list delimited list of Request IDs that a user is trying to act upon." So there is no need for you to be trying to do this yourself.
Am I supposed to get the state data back from the parent's page query string?
No, not when authenticating within a canvas/page tab app. The only query string parameter that gets passed to your app in this scenario is the content of the app_data parameter.
But you don’t need the state parameter in this scenario – verifying the signed_request is absolutely sufficient, because it’s signed with your app secret, that only you and Facebook know. So that is enough protection against “manipulated” requests right there already.
See https://developers.facebook.com/docs/authentication/canvas/ resp. https://developers.facebook.com/docs/authentication/pagetab/ for more details. (And see how they do not mention the state parameter at all.)
Edit:
I am storing the user to user request Id in the state parameter. For example A invites B to participate in the app via a facebook request. Once B authorises the app A needs to be rewarded. So I need to know that B came to the app following A's invitation. Therefore I store the requestId in the state param, so once B has authorised the app I can take appropriate action.
That’s a misuse of the state parameter … it’s supposed to achieve something completely different (CSRF protection, as the docs say).
While this might work in your scenario – why are you not using the app_data parameter to transmit this piece of information? That’s the designated way of transferring info to canvas/page tab apps.

Facebook PHP SDK - getLoginUrl() - state value

I am using the PHP SDK getLoginUrl() function which works perfectly to log the user in. Once the user is redirected back to my page, the URL can come in two forms, see in the following link subsection 3: http://developers.facebook.com/docs/authentication/server-side/
Part of the return URL is a ?state= value. This value is supposed to be used to prevent Cross Site Request Forgery: http://developers.facebook.com/docs/reference/dialogs/oauth/
Though, using the getLoginUrl() method I can never set a state value as it is not one of the parameters: http://developers.facebook.com/docs/reference/php/facebook-getLoginUrl/
So how can I utilize the state-value to log a user into facebook and prevent CSRF?
So how can I utilize the state-value to log a user into facebook and prevent CSRF?
This is being automatically handled by the Facebook PHP SDK. If you were about to write your own API calls to Facebook, you would need to submit the state manually (if desired) as per Facebook's OAuth documentation.
When you create a login url with BaseFacebook::getLoginUrl(), the first thing the function does is to establish CSRF token state1, which creates a hash using PHP's core mt_rand(), uniqid() and md5() functions and also stores the value as a session variable.
When the user gets redirected back to your page the, FBSDK checks if the submitted state matches the state value in the session. If the values indeed match, the state is cleared from the Facebook object and from the session, so all subsequent getLoginUrl() requests would get a new state variable.2
Theoretically you could use your own state value with FBSDK by writing it to fb_<your_app_id>_state session variable before constructing the Facebook-object, as the BaseFacebook's constructor and establishCSRFTokenState() both check if the state already exists in the session.
But that would probably introduce more complexity than is necessary.
see BaseFacebook::establishCSRFTokenState()
see BaseFacebook::getCode()

Sometimes Facebook doesn't return the auth_nonce parameter during authentication

I am using the auth_nonce parameter during the server-side authentication flow. However, I'm getting a problem where sometimes Facebook doesn't return the auth_nonce argument in the final step, which of course causes the authentication to fail.
Often it works just fine. These cases are when the user is initially logging in to my application, and I request that Facebook reauthenticate them (auth_type=reauthenticate). I've never seen this fail.
When it does fail, it's always after the user has logged in, and their auth_token has expired, and I'm silently reauthenticating them between page loads to get a new auth_token.
In these latter cases, the URL redirection looks something like this:
http://myapplication.url (notices token is expired, so sends the user to...)
https://www.facebook.com/dialog/oauth?client_id={APP_ID}&redirect_uri=http%3a%2f%2fmyapplication%2eurl%2ffacebook%2fafterlogin&scope=list,of,permissions&display=page&auth_nonce=Vr6EgapnMFIKrbMtVrdcZDTbioGe715pWDtMveA8z4xVNMR5IzGYoPN3rSxf (Facebook redirects them to...)
https://www.facebook.com/dialog/permissions.request?app_id={APP_ID}&display=page&next=http%3A%2F%2Fmyapplication.url%2Ffacebook%2Fafterlogin&response_type=code&auth_nonce=Vr6EgapnMFIKrbMtVrdcZDTbioGe715pWDtMveA8z4xVNMR5IzGYoPN3rSxf&fbconnect=1&perms=list%2Cof%2Cpermissions (Finally, we get redirected back to...)
http://myapplication.url/facebook/afterlogin?code={Big long code here}#_=_
During that last call, I GET the following URL:
https://graph.facebook.com/oauth/access_token?client_id={APP_ID}&redirect_uri={THE_PROPER_REDIRECT_URL}&client_secret={APP_SECRET}&code={Big long code here}
The reply I get back is in the form:
access_token={AUTH_TOKEN}&expires=5083
According to the documentation (and my experience during normal authentication), there should be a auth_nonce parameter in the final reply which I can validate.
Am I doing something wrong here?

facebook oauth authentication doesn't return "code" parameter

I'm trying to use facebook's oauth.
Basically facebook has to return me a "code" parameter.
But i get nothing, it just return my callback url (to the exact same url).
i'm generating this url with my app.
http://www.facebook.com/dialog/oauth?client_id=76209388873&redirect_uri=http%3A%2F%2Ffb.lous%2Fmain%2Ffacebook_callback&scope=read_stream
I used other parameters and options, just when i set response_type=token
i get parameter list for javascript (with # character instead of ?, its for client side, i'm trying to write some api bot)
So right now i can't get any parameter with someway.
I tried to solve exactly the same thing for several hours. In my case it turned out to be a stupid redirect problem. Facebook correctly redirected back to http://www.mysite.com with the code parameter, then my webapp redirected to http://www.mysite.com/users/login (because the user wasn't logged in yet). On the second redirect I lost the code parameter.