Announcement Announcement Module
Collapse
No announcement yet.
Facebook connection detection Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Facebook connection detection

    Assuming a facebook is already establish from the frontend. (Javascript or some other means)

    How can we use use spring social to detect it and add it to the UsersConnectionRepository

    Example:
    userId = Long.toString(userIdSequence.incrementAndGet());
    ConnectionRepository repository = connectionRepository.createConnectionRepository(us erId);

    connectionRepository.createConnectionRepository(us erId).addConnection(connection);

    userCookieGenerator.addCookie(userId, response);
    SecurityContext.setCurrentUser(new User(userId));

    How do we get the facebook connection to be added.

  • #2
    There's not (yet) any real integration between Spring Social's server-side Facebook stuff and Facebook's client-side stuff. That is more or less the subject of https://jira.springsource.org/browse/SOCIALFB-40, although the text in that issue speaks more of solving the problem in the other direction. I invite you to share any thoughts/ideas you may have as comments on that issue and vote for it. It's currently not very high on my priority list, but if I get enough feedback and interest I'll be happy to bump it up.

    Comment


    • #3
      Sorry i am new to all this.

      What i am looking at is only manually adding of the facebook connection like a provider into UsersConnectionRepository.

      I can't use MVC view to "control" the connection to "signin/facebook"

      the solution provided seems to be the other way round.

      Comment


      • #4
        Right...and that's what I said in my earlier response: "...the text in that issue speaks of solving the problem in the other direction." Truly that issue should reflect a more general (either direction) approach for integrating the client-side stuff with the server-side stuff.

        That said, it's not impossible to solve the problem with Spring Social as-is: There's no reason why you can't create a controller that is injected with the ConnectionRepository and uses it to save a connection...a connection that is created from the token given to it from the client-side. You can create the connection by calling createConnection() on the FacebookConnectionFactory, passing in an AccessGrant instance.

        It's a lot more manual work on your part (which is why it'd be nice for Spring Social to directly support it), but it can be done.

        Comment


        • #5
          Tried to change the code to something like this but got an MissingAuthorizationException
          Code:
          AccessGrant accessGrant = new AccessGrant(accessToken);
          OAuth2ConnectionFactory<?> connectionFactory = (OAuth2ConnectionFactory<?>) connectionFactoryLocator.getConnectionFactory(Facebook.class);
          Connection<?> connection = connectionFactory.createConnection(accessGrant);

          Comment


          • #6
            Hi

            The code you posted does work if you pass in a valid accessToken and if you have registered a Facebook connection factory with the locator with a valid clientId and secret. I just ran this locally and I did get a MissingAuthorizationException if the accessToken is blank, but with a valid access token this gave me a connection I could use to retrieve user profile data from Facebook.

            Can I ask how you are getting the value of the access token you are passing in?

            Facebook provides a "code" parameter in its callback from the permissions dialog that the user approves when they give access to your application. The "accessToken" in the your code must be the access grant that is given by Facebook in exchange for this code - not the code itself. If you do have access to the "code" parameter given in the callback from the permissions dialog, instead of using the AccessGrant constructor in your code above, you can retrieve the access grant as follows:

            AccessGrant accessGrant = connectionFactory.getOAuthOperations().exchangeFor Access(code, redirectUrl, null);

            where redirectUrl is your application url that Facebook redirected to when it passed back the "code" parameter.

            Hope this helps

            Comment


            • #7
              As mentioned earlier. I could not use the provider (signin/providerId) [server side]. If i use that connection will be stored in the DB

              Objective is to add a connection to DB if the FB connection is already established and not expired.

              Sample of call to retrieve accessToken
              Code:
              https://graph.facebook.com/oauth/access_token?client_id=....&client_secret=....&grant_type=client_credentials

              Comment


              • #8
                Instead of retrieving the access token using the "/oauth/access_token" endpoint, could you make the following call:

                https://graph.facebook.com/oauth/authorize?client_id=...&response_type=code&redirec t_uri=<your-redirect_url>

                I'm not sure of how your users are connecting with Facebook initially, but I'm wondering if a user is already connected if this call will result in a response containing a "Location" header in which the "code" is specified. If so, you could then use the exchangeForAccess method to exchange this code for an access token.

                Comment


                • #9
                  I guess I'm not understanding what you want to do. My understanding is that the user has already authorized your application, but via client-side JavaScript and not with server-side Spring Social stuff. But what you want to do is detect that it has happened already and use the associated access token to create a connection in Spring Social. Is that not what you are wanting to do? If not, then please help me understand where I'm wrong.

                  If it is correct, then it wouldn't take much to write some client-side JavaScript (using FB's JS API) to detect the authorization and, upon determining that there is an existing authorization, send the details of that authorization (via a REST call to some controller on the server-side) which then creates a Connection (using the FacebookConnectionFactory) and then persists that connection (using the UsersConnectionRepository).

                  The missing pieces in all of this are the client-side code that detects the connection and sends it to the server and the server-side controller that coordinates the creation of the connection. I know that FB's JS API can do what you need (although I don't have the code for it handy).

                  Comment


                  • #10
                    Michael makes another good point...

                    If the user has already authorized your app, then hitting the authorization endpoint should result in an immediate redirect to a URL containing the authorization code (that you can then exchange for an access token)...and that redirection URL is probably in the Location header (I'm curious enough that I'm probably going to try this sometime today). If the user hasn't already authorized your app, then Facebook would return an authorization page. The trick here that I think Michael is suggesting is to hit that URL via RestTemplate or some such mechanism rather than actually redirecting to it as you'd normally do. That way the user isn't bothered with a redirect and it gives you a chance to programmatically inspect the Location header.

                    As I said, I'm curious about this now...so I'm going to try it and let you know.

                    Comment


                    • #11
                      Unfortunately, Michael's idea (although on the surface a solid one) doesn't work. Even with an established authorization, the Location header is empty and it appears that FB uses JavaScript code to do the redirect. (I say it "appears" because the body of the response is rich with JS and at least some portion of that JS code checks for a cookie and does a redirect if it *is* found, but it's a bit obfuscated and I've not bothered digging any deeper into it.) I did, however, try a diff between the response bodies for both authorized and non-authorized and found that they were essentially identical (only a few timestamp values seemed to differ).

                      That said, it may be possible to *detect* an existing authorization by checking for the existence of those cookies. Actually getting the info out of them to create a connection may prove more difficult, however. At one time it was fairly easy to do, but then FB changed their cookie structure and I can't say for sure what's in there now. Sounds like I need to do another investigation into the contents of the cookie. I can say that if the access token is available in the cookie then you should be able to get at it using @CookieValue (but that would require you to write a Spring MVC controller to receive it).

                      Comment


                      • #12
                        I was initially thinking that RestTemplate could be used for this call, but after some more thought I'm not sure if this would work.

                        If the user had authorized the application via client-side Javascript it would be their browser session which retained the authorization (via cookies?), so for the RestTemplate approach to work the Facebook cookies or some session id would need to be sent via RestTemplate.

                        An alternative could be to hit the authorization endpoint using Javascript using AJAX or some other mechanism and inspect the response for the location header - not sure if there are any restrictions on doing this? Or even better, as Craig suggested, if the Facebook JS client-side library supported obtaining the current authorization code, you could then pass this over to the server-side controller which could exchange for an access token.

                        Comment


                        • #13
                          Looks like my last reply overlapped with Craig's last reply. After further reflection, I don't think an AJAX approach can't be used because response headers can't be accessed, but I think I have found a (low tech) way of detecting a connection which was instigated by a spring-social app.

                          A simple hidden frame embedded in a page, with src="https://graph.facebook.com/oauth/authorize?client_id=...&response_type=code&redirec t_uri=<your_redirect_url>" will result in a callback to your_redirect_url with a code parameter if the user is already logged in. If you have a controller at <your_redirect_url> which takes this code, exchanges for an access token and creates your connection, I think this may work.

                          In fact, this is exactly what the ProviderSignInController does - if you register a ConnectionSignUp instance with your UsersConnectionRepository and register a ProviderSignInController with your application, you could get implicit sign up by having a hidden frame with "https://graph.facebook.com/oauth/authorize?client_id=...&response_type=code&redirec t_uri=http://localhost:8080/signin/facebook>" for example.

                          As I mentioned above - this seems to work when facebook authorization has been generated using the spring-social authorisation flow - what I don't know is whether this approach would work if the authorization was instigated by Javascript
                          Last edited by michaellavelle; Jul 18th, 2012, 11:01 AM.

                          Comment


                          • #14
                            Good point on the cookies...I clearly hadn't had enough of my morning caffeine when first thinking about it.

                            That's a nice tip...and I suspect it would work. But it is a bit kludgy/hackish. A cleaner approach, I think, would be to let some JS determine the authorization status and send the details of the authorization (access token, et al) to the server-side for the purposes of establishing a connection in Spring Social. I'm reasonably certain that will work, although it would require some JS on the client-side and some custom (e.g., not currently implemented in Spring Social) server-side work to receive the authorization details.

                            As long as the client-side code and the server-side code are using the same App ID when working with FB, the authorization-stuff should work fine between both sides because it's the same authorization. (e.g, same App ID, same authorization.)

                            Comment


                            • #15
                              The trick of using js to pass access token works

                              Comment

                              Working...
                              X