Retrieve Facebook profile data in Java: Scribe

In a series of blogposts I’ll describe how to retrieve a Facebook profile using several OAuth2 libraries for Java and Spring MVC. The first example is for Scribe.

Setup

The Maven dependency for Scribe:

<dependency>
    <groupId>org.scribe</groupId>
    <artifactId>scribe</artifactId>
    <version>1.3.5</version>
</dependency>

First you need to register an application with Facebook. Then add an HTML snippet to your site that triggers the login flow:

<a href="/auth/facebook">Get my Facebook profile</a>

We create a Spring Controller and inject the Facebook client id, client secret and the host of our application:

@Controller
public class FacebookScribeAuthenticator {

  public static final String STATE = "state";
  private String applicationHost;
  private OAuthService oAuthService;
  // Jackson ObjectMapper
  private ObjectMapper objectMapper;

  @Autowired
  public FacebookScribeAuthenticator(
      @Value("#{properties['facebook.clientId']}") 
      String clientId,
      @Value("#{properties['facebook.clientSecret']}") 
      String clientSecret,
      @Value("#{properties['application.host']}") 
      String applicationHost) {
    this.applicationHost = applicationHost;
    this.oAuthService = buildOAuthService(clientId, clientSecret);
    this.objectMapper = new ObjectMapper();
    this.objectMapper.registerModule(new AfterburnerModule());
  }
}

private OAuthService buildOAuthService(String clientId, 
                                       String clientSecret) {
  // The callback must match Site-Url in the Facebook app settings
  return new ServiceBuilder()
      .apiKey(clientId)
      .apiSecret(clientSecret)
      .callback(applicationHost + "/auth/facebook/callback")
      .provider(FacebookApi.class)
      .build();
  }
}

Start the authentication

Now we add a @RequestMapping to start the OAuth2 authorization flow. To prevent CSRF we add and store a state parameter that should be returned by Facebook. Scribe doesn’t handle this parameter in its API, so we have to add it to the authorization URL.

@RequestMapping("/auth/facebook")
public RedirectView startAuthentication(HttpSession session) 
    throws OAuthSystemException {
  String state = UUID.randomUUID().toString();
  session.setAttribute(STATE, state);
  String authorizationUrl = 
      oAuthService.getAuthorizationUrl(Token.empty()) 
        + "&" + STATE + "=" + state;
  return new RedirectView(authorizationUrl);
}

When the user goes to /auth/facebook, he is redirected to the Facebook authentication URL. If it’s his first visit, he has to approve the access to his data for your application:

Facebook approval

Handle the callback

After the user has approved the access to his profile, he is redirected to our callback endpoint with two request parameters: code and state. The code is the authorization code that can be exchanged for an access token. The state parameter should have the same value as we have sent to Facebook in the authorization request.

In case of failure we redirect the user to /login. If we can retrieve the user’s Facebook user id successfully, he is redirected to /logged-in.

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

  // Exchange the code for an AccessToken and retrieve the profile
  Token accessToken = getAccessToken(code);
  Response response = getResponseForProfile(accessToken);
  if (!response.isSuccessful()) {
    return new RedirectView("/login");
  }

  // Store the Facebook user id in the session and redirect the user
  // to the page that needs the profile.
  String facebookUserId = getFacebookUserId(response);
  session.setAttribute("facebookUserId", facebookUserId);
  return new RedirectView("/logged-in");
}

Retrieve the AccessToken

The Token.empty() is passed because Scribe’s OAuthService handles both OAuth1 and OAuth2 providers.

private Token getAccessToken(String code) {
  Verifier verifier = new Verifier(code);
  return oAuthService.getAccessToken(Token.empty(), verifier);
}

Get the Facebook profile data

Anyone can access the public profile data for https://graph.facebook.com/<userId>, but you need to be logged in to get https://graph.facebook.com/me

private Response getResponseForProfile(Token accessToken) {
  OAuthRequest oauthRequest = 
      new OAuthRequest(Verb.GET, "https://graph.facebook.com/me");
  oAuthService.signRequest(accessToken, oauthRequest);
  return oauthRequest.send();
}

Facebook will return the profile as JSON (I know, this is not my profile):

{
 "id":"4",
 "name":"Mark Zuckerberg",
 "first_name":"Mark",
 "last_name":"Zuckerberg",
 "link":"https:\/\/www.facebook.com\/zuck",
 "username":"zuck",
 "gender":"male",
 "locale":"en_US"
}

We use Jackson to get the Facebook identifier from the JSON response:

private String getFacebookUserId(Response response) 
    throws IOException {
  String responseBody = response.getBody();
  JsonNode jsonNode = objectMapper.readTree(responseBody);
  JsonNode idNode = jsonNode.get("id");
  return idNode.asText();
}

Now you have the Facebook user id in the HttpSession. In the next blogposts I’ll explain how to do this with other Java libraries.

Posted in Development, Geen categorie, Social Media, Technology, tools Tagged with: , ,
0 comments on “Retrieve Facebook profile data in Java: Scribe
2 Pings/Trackbacks for "Retrieve Facebook profile data in Java: Scribe"
  1. […] the previous blogpost I explained how you can get Facebook profile data using Scribe. This blogpost will do the same for […]

  2. […] previous blogposts I explained how you can get Facebook profile data using Scribe or Spring Social for the OAuth 2 handling. In this article you can read how to get the profile […]

Archives

Categories