I had a lot of problems trying to get the client-side login to work, so I'm going to allow myself to refer to a ton of other questions here ... none of them gave an answer that worked for me.
CONTEXT
- Logging on to the server server works fine
- Client-side login using the JS SDK works fine in Safari * (not tested on Firefox or IE or a mobile device without Chrome), but not on Chrome , which is the issue (and most of my users use Chrome, so he is very important).
- Gem Options:
- ruby (2.1.2)
- rails (4.1.1)
- oauth (0.4.7)
- oauth2 (1.0.0)
- omniauth (1.2.2)
- omniauth-facebook (2.0.0)
- omniauth-oauth2 (1.2.0)
- This is for an application in development mode where, as a developer, Iβm definitely allowed to enter the system
* The work is excellent, I mean, if you just copied the code from Rails Bates RailsCast ( http://railscasts.com/episodes/360-facebook-authentication?view=asciicast ) it works without any additional anything
TL: DR; I am passing the following url which should work ...
`http://localhost:3000/auth/facebook/callback?signed_request=ASDF.JOUYOUY`
... but I still get the error OmniAuth::Strategies::Facebook::NoAuthorizationCodeError (must pass either a code parameter or a signed request (via signed_request parameter or a fbsr_XXX cookie)):
TROUBLESHOOTING FOR DATE + OVERVIEW OF MANY OTHER ERRORS / POTENTIAL SOLUTIONS
The following code solutions are built on Rails Bates RailsCast code:
$('#sign_in').click (e) -> e.preventDefault() FB.login (response) -> window.location = '/auth/facebook/callback' if response.authResponse
Obstacle # 1: are third-party cookies blocked?
It does not necessarily lead to an error, it just makes it impossible for you to connect the application to Facebook.
To connect your application to Facebook, you first need to be logged in with Facebook, because the code FB.login (response) -> window.location = "/auth/facebook/callback" if response.authResponse depends on the validity of the authResponse and the contained it contains the signedRequest parameter.
If cookies are blocked (i.e. Chrome settings> Advanced settings> Privacy> Content settings> Block third-party cookies checked), you will never get an authResponse object. This is a combination of questions / answers here: FB.getLoginStatus always returns status = 'unknown' . In other words, if you execute FB.getLoginStatus , no matter how many times you click the Login button, the status will always return as unknown for documents: https://developers.facebook.com/docs/reference/javascript/FB. getLoginStatus .
The solution for the code is still ... : If FB.login returns an unknown redirect response back to the server login.
$('#sign_in').click (e) -> e.preventDefault() FB.login (response) -> if response.status is "unknown" window.location = "/auth/facebook" else window.location = "/auth/facebook/callback"
Obstacle # 2: Are the parameters appropriate accordingly?
If you have disabled third-party cookies, you may encounter an error:
OmniAuth::Strategies::Facebook::NoAuthorizationCodeError (must pass either a `code` parameter or a signed request (via `signed_request` parameter or a `fbsr_XXX` cookie)):
Despite setting cookie: true in FB.init , sometimes parameters are not passed yet. As indicated in:
... you may need to manually pass the signed_request parameter. Quick observation. Per Facebook docs ( https://developers.facebook.com/docs/facebook-login/using-login-with-games ), signedRequest must have two components separated by a character . . I donβt know how, but I got one without . earlier. Separation is important because the second half, which is a base64url encoded JSON object, contains code information.
Code Solution so far ... : add the signed_request parameter for the return URL
$('#sign_in').click (e) -> e.preventDefault() FB.login (response) -> if response.status is "unknown" window.location = "/auth/facebook" else window.location = ("/auth/facebook/callback?signed_request=" + response.authResponse.signedRequest)
Obstacle # 3: still nothing ... is still the same error as # 2
Maybe only me at this moment?
Code Solution so far ... : go super pedantic, signedRequest code from signedRequest and add the callback URL
$('#sign_in').click (e) -> e.preventDefault() FB.login (response) -> if response.status is "unknown" window.location = "/auth/facebook" else parsed_signed_Request = response.authResponse.signedRequest.split(".") key_info = base64_decode(parsed_signed_Request[1]) // decoded via http://www.simplycalc.com/base64-source.php key_info_object = jQuery.parseJSON( key_info ) window.location = ("/auth/facebook/callback?code=" + key_info_object["code"])
Obstacle # 4: CSRF detected, but not for why you think
Now I went straight to the brick wall. When I run the code as above, I get a CSRF error. There is some reason to get this error:
- You may get this error if your Facebook application is in Dev mode and you are trying to log in. In this case, the FB does not allow registered developers not on the list. See the first answer to this question: Rails + omniauth + facebook - csrf detected
But the problem in my case was not higher, and the code parameter was presented without the state parameter. Now there were answers saying that you can fix this by setting provider_ignores_state: true in the omniauth.rb configuration file, see the second answer to the question mentioned above, but this is not a problem for me. What for? Because 1) I donβt like the rotation specifically designed to counteract CSRF, and 2) it appears when the settings are started only for entering the server. Adding it just didn't do anything for me.
This means that the big problem with solution # 3 was that he tried to combine the server-side login approach (accepts the code and state parameters) using the client-side login approach (accepts signed_request param).
This means that I will return to the original question ... how to pass signed_request so that the client login works?
Since I have tried this many times, let me point out another mistake that I saw. This has answers related to Facebook errors ( Work with Oauth 2.0-facebook gem error 100: This authorization code was used ), but besides this, I found something else that could cause it.
As indicated in this lesson ( https://coderwall.com/p/bsfitw ), you match the callback route through both get and post , but when I do this, my logger shows two requests on Facebook, the second one is obviously blocked and causes an error. (Also means that the first request has passed, and the user has already logged in / the data has been saved, whatever). My solution was to set the route as follows:
match 'auth/:provider/callback', to: 'signups#create_facebook', via: [:get]