Go to content

Retrieve Facebook profile data in Java: Spring Social

Published on

In the previous blogpost I explained how you can get Facebook profile data using Scribe. This blogpost will do the same for Spring Social.

Setup

The Maven dependency for Spring Social Facebook:

<dependency>
  <groupId>org.springframework.social</groupId>
  <artifactId>spring-social-facebook</artifactId>
  <version>1.0.3.RELEASE</version>
</dependency>

Setup of the Spring controller:

@Controller
public class FacebookSpringSocialAuthenticator {
  public static final String STATE = "state";
  private String applicationHost;
  private FacebookConnectionFactory facebookConnectionFactory;

  @Autowired
  public FacebookSpringSocialAuthenticator(
      @Value("#{properties['facebook.clientId']}") 
        String clientId,
      @Value("#{properties['facebook.clientSecret']}") 
        String clientSecret,
      @Value("#{properties['application.host']}") 
        String applicationHost) {
    this.applicationHost = applicationHost;
    facebookConnectionFactory = 
      new FacebookConnectionFactory(clientId, clientSecret);
  }
}

Start the authentication

@RequestMapping("/auth/facebook")
public RedirectView startAuthentication(HttpSession session) 
    throws OAuthSystemException {
  String state = UUID.randomUUID().toString();
  session.setAttribute(STATE, state);

  OAuth2Operations oauthOperations = 
      facebookConnectionFactory.getOAuthOperations();
  OAuth2Parameters params = new OAuth2Parameters();
  params.setRedirectUri(applicationHost + "/auth/facebook/callback");
  params.setState(state);

  String authorizeUrl = oauthOperations.buildAuthorizeUrl(
      GrantType.AUTHORIZATION_CODE, params);
  return new RedirectView(authorizeUrl);
}

Handle the callback

@RequestMapping("/auth/facebook/callback")
public RedirectView callBack(@RequestParam("code") String code,
                             @RequestParam("state") String state,
                             HttpSession session) {
  String stateFromSession = (String) session.getAttribute(STATE);
  session.removeAttribute(STATE);
  if (!state.equals(stateFromSession)) {
    return new RedirectView("/login");
  }

  AccessGrant accessGrant = getAccessGrant(code);

  String facebookUserId = getFacebookUserId(accessGrant);
  session.setAttribute("facebookUserId", facebookUserId);
  return new RedirectView("/logged-in");
}

Retrieve the AccessGrant

private AccessGrant getAccessGrant(String authorizationCode) {
  OAuth2Operations oauthOperations = 
      facebookConnectionFactory.getOAuthOperations();
  return oauthOperations.exchangeForAccess(authorizationCode,
      applicationHost + "/auth/facebook/callback", null);
}

Get the Facebook user id

Spring social splits up the profile response into several classes. With Connection#fetchUserProfile you get the username, but not the user’s identifier, which is retrieved with Connection#getKey.

private String getFacebookUserId(AccessGrant accessGrant) {
  Connection<Facebook> connection = 
      facebookConnectionFactory.createConnection(accessGrant);
  ConnectionKey connectionKey = connection.getKey();
  return connectionKey.getProviderUserId();
}

Conclusion

Spring Social has built in methods to convert the JSON response of the profile into Java objects which Scribe doesn’t do for you. Its setup is a bit simpler and there are no traces of OAuth 1 support in the Facebook classes. Spring social seems to handle the flow a bit slower (200-300 ms slower) than Scribe.