Here's the gist of it:
- ProviderSignInController handles the request to /signin/{provider ID}.
- If it's an OAuth 1 provider, it fetches a request token next.
- Then, regardless of whether it's OAuth 1 or OAuth 2, it redirects to the provider's signin page.
- At that point, if the user is already signed into the provider, it will prompt the user to authorize the app. If the user isn't signed into the provider, it will prompt the user to sign in and then authorize the app. Note that all of this step takes place at the provider and the behavior here is defined by the provider (and is different for Facebook, Twitter, LinkedIn, etc)
- After the user authorizes the app, the provider redirects back to the app, where ProviderSignInController receives the callback.
- ProviderSignInController uses what it receives from the callback (it differs depending on whether it's OAuth 1.0 vs. OAuth 1.0a vs. OAuth 2) to retrieve an access token.
- ProviderSignInController fetches the user's identifying information from the provider (usually a numeric ID...that's certainly what it is with Facebook).
- ProviderSignInController compares that user's provider ID with existing connections in the database.
- If an existing connection matches, then the local user belonging to that connection is signed in via the SignInAdapter. The SignInAdapter exists so that you can implement any security mechanism you want and so that Spring Social isn't coupled to Spring Security.
- If no existing connection matches, then ProviderSignInController will place the connection details in session (as a ProviderSignInAttempt) then redirect to the application-provided signup (aka, registration) page.
- After the user registers, the application can use ProviderSignInUtils to create a connection between the newly registered user and the provider using the ProviderSignInAttempt that was placed in session.
I assume that you're looking at the spring-social-quickstart example. In that example UserInterceptor is just a simple (somewhat hackish) approach to application security since the sample doesn't use Spring Security. In other samples, such as Spring Social Showcase, Spring Security *is* in play, so there is no such interceptor. My point here is to not place too much emphasis on UserInterceptor as it's just for that sample and not really part of Spring Social.
ConnectionSignUp comes into play when you want to implicitly sign in a user. It's optional (and other samples such as spring-social-showcase don't use it). The idea is that your app doesn't necessarily keep a database of existing users and instead wants to use whatever info it receives from the provider as user data. In the case of spring-social-quickstart, there is no user database, but when the user authorizes with Facebook, the user's Facebook data is retrieved and used to create a user on-the-fly and without going through a signup screen. The call to ConnectionSignUp happens in JdbcUsersConnectionRepository when the connection data is being used to try to find an existing connection in the DB--if no connection can be found and if the ConnectionSignUp is not null, then it will create the user and a connection on-the-fly. Again, this feature is optional.
(Note: As JdbcUsersConnectionRepository is currently the only implementation of UsersConnectionRepository, it's handy to have the code for working with ConnectionSignUp in there. There's opportunity for refactoring to extract common code such as this from JdbcUsersConnectionRepository into a base class for other non-JDBC-based implementations to work with.)
The ConnectionSignUp isn't given just a user ID...it's given a Connection. That Connection includes some details in ConnectionData, among which is providerUserId, which is the user's ID on the provider (e.g., their Facebook ID). That information is ultimately populated from each provider's implementation of ApiAdapter (it's FacebookAdapter in the case of Facebook).
ConnectionSignUp's execute() method also returns a user ID. In that case, the ID it returns is the local application's ID for the user that it creates on-the-fly. In the quickstart example, it's rather simplistic, generating the ID from an AtomicLong, but your implementation of the ConnectionSignUp interface could do whatever you want (you could even go so far as to actually write a record to the database for the on-the-fly user and return the primary key as the ID).
Craig Walls
Spring Social Project Lead