This forum is now a read-only archive. All commenting, posting, registration services have been turned off. Those needing community support and/or wanting to ask questions should refer to the Tag/Forum map, and to http://spring.io/questions for a curated list of stackoverflow tags that Pivotal engineers, and the community, monitor.

Facebook Provider Sign-in Problem.

Apr 5th, 2012, 01:02 PM

Good day ,

I am having a small problem with my web app . I am trying to use spring social to provide a Facebook login feature for my app. I have a database with my local users accounts (PostgreSQL) and I'm using hibernate .

So far this is what i have accomplished. When a user comes to the sign in page , he/she can login using their username and password or click a <Sign-in with Facebook> button. When they click the button it posts to /signin/facebook and the ProviderSignInController kicks in and connects to Facebook , does the authentication and then sends the user to the signup page where it pre-fills some the fields (First Name , Last Name , email address) from the Facebook profile. they can then fill out the remaining fields and submit , where it saved to my database. I have a field in my database account table that stores the Facebook userid.

My problem is now , even after the account is created , when i click the <sign-in with Facebook> button , after it does the authorization by Facebook and redirects , it still doesn't make the link to the local user account , and prompts the user to sign up again .

I know where my problem lies , its a matter of how to fix it . I am trying to figure out how exactly the providersignincontroller tries to match the Facebook account to my local users account.

Based on what you said first I would check UserConnection table which maps your local userid to the providerUserid. If that is looks good I would then check SignInAdapter which you provide to ProviderSignInController. ProviderSignInController will call your SignInAdapter's signIn method where you have to do the user login yourself by populating the securityContext.

Comment

You say you have an account table that includes the Facebook user ID...that's fine if it helps your application code somehow, but that's not enough for Spring Social. Spring Social wants to manage connections in a UserConnection table. This table essentially joins the application-specific user ID with a provider (e.g., Facebook, Twitter) account as well as a few other bits of info about the connection.

After your code saves the new account info to the database, do you follow that up with a call to ProviderSignInUtils.handlePostSignUp()? If not, then the connection is never created in the UserConnection table.

For example, the Spring Social Showcase example has the following code that handles the signup form submission:

Notice near the end, after the account has been created successfully (and is not null), the code uses SignInUtils to automatically sign the user into the application and then uses ProviderSignInUtils.handlePostSignUp() to complete the connection between the newly created user and the provider (e.g., Facebook).

Comment

hi , i solved the problem using the information you provided. Thank you very much . I understand where the users connection comes into play now. however one thing though . if i restart my server the user connections are lost. how can i save these connections to a table in my db ?

Comment

With Spring Social Showcase, it's using an in-memory database, which is great for demos and development, but horrible for production for the reasons you've just given. I'm assuming that the reason your connections are lost is because you're using the embedded database. Rather than use the embedded database, you should use a datasource that's tied to a real DB.

Comment

Thank you Craig , I got it working by creating the userconnection table in my db and pointing the datasource to it. Everything works fine now. The only thing i noticed when i created the table is that i had to change refreshtoken and secret fields from not null to allow nulls because this was throwing an error.

Comment

ok thanks. i have another question , i have the provider sign-in working perfectly now , i now want to add some additional Facebook functionality to my app , however if i use connect/facebook it creates an additional connection in my user connections table which i do not want. i know i can simply extract the access token from the table and use it , but i want to use spring social functions .

Comment

I'm not clear on what you're saying...are you saying that you use Provider Sign-In for authenticating into your app (which creates a connection if one didn't already exist) and then go through the ConnectController flow again (which would create another connection)? If so, that's not how it was intended to be used.

The idea is that if the user has previously created a connection with ConnectController, then they can sign in to the application using ProviderSignInController and not have to enter their app credentials...the previously-established connection will serve as authentication. But, if they haven't created a connection before, then ProviderSignInController can let them sign in via Facebook (or some other provider) and create a new account that is already connected to the provider. There would be no need to go through the connection flow again, because the account would already be connected to the provider (Facebook, in your case).

If that's not what you're saying, then please clarify.

Comment

I'm sorry if i didn't make myself clear. what I really wanted to find out is how to get extract a Facebook connection from the users connection repository so i can create a Facebook template object and perform Facebook operations. I have already realized that i don't need to to use connectController. at present what i do is manually retrieve the accesstoken from my userconnection table and then create the Facebook template object from that.

Comment

One of the main benefits of Spring Social is that (unless you want to), you don't ever have to deal with OAuth yourself. You configure the connection factory with the app's key and secret and then you're done dealing with OAuth. You can then ask the connection repository for a connection and from that get the API binding.

Comment

here lies my problem. when i try to do this . my facebook object is null. its not finding the connection in the connectionRepository. remember i had previously modified my application to user a local userconnections table. i'm not sure if this is what is causing the problem.

Comment

That doesn't make much sense to me: You say that the connections are being written to the UserConnection table, but the connection repository can't find them? If it's the same connection repository wired with the same data source, then I don't see how the connection repository wouldn't be able to find that table. The connection repository was responsible for storing those connections in the first place, so why couldn't it find them when you later ask for them?

Would you mind posting the pertinent configuration here? At this point I'm just speculating (and not even able to do that effectively)...perhaps seeing how you've configured these beans would make a difference.

Comment

I must admit that I'm a bit stumped. I'm sure there's some key info that I'm either overlooking or isn't presented here. I've stared at this code you've shared for quite awhile and see nothing obvious that's out of place.

But it seems to me that if in the course of a provider sign-in a connection is, in fact, created in the database, then that connection should be found later when findByPrimaryConnection() is called.

That assumes, of course, that the authenticated user is the same authenticated user for which the connection was created. Ultimately, the query performed is as follows:

Where the userId is the same as whatever value is passed into createConnectionRepository() and providerId is whatever the provider connection factory says it is for the given API interface (in the case of Facebook, it will be "facebook").

Can we be sure that the connection is created for the very same user for whom the authentication is retrieved when creating the connection repository? More specifically, can we confirm that the userId field in the UserConnection table holds the same value as the value returned from authentication.getName()?

To help with that, you might want to do a bit of debugging in the connectionRepository() method of your SocialConfig.java and then compare what is passed into createConnectionRepository() with what is in the userId field in the UserConnection table.

That's the only theory I have right now. Once your eliminate or confirm that as the issue, I can keep looking.