Facebook user authentication in Java web application

Posted by in Blog | June 21, 2012

Facebook is the biggest social networking website intended to connect friends, family, and business associates. With over 800 million users and counting, application developers are in need of user information integration with the biggest social network. That means using Facebook user data as the primary authentication mechanism in their applications and/or reading user data from Facebook so the user doesn’t have to fill out annoying registration forms.

As of May 2008, Facebook has discontinued any support of their official Java client, directing users interested in developing Facebook applications in Java to use one of the various third-party clients out there. But using third-party solutions is not always trivial; usually they are complex API collections with limited documentation. For designing beer fan site fanklub.karlovacko.hr we have created our own Facebook integration mechanisms.

Note that this functionality can be used in any Java web application environment or framework (like Oracle ADF, Spring, Jboss Seam, etc.) as it uses default Java servlet implementation (take a look at one of our previous blog posts, Java/JEE software development frameworks).

First thing you’ll have to do in order to connect to Facebook is to create a Facebook application. Go to developers.facebook.com and log in with your Facebook account. You need to have a verified account (i.e. give Facebook your mobile phone or credit card number) to be able to create applications. Go to “Apps” and click “Create New App”. The dialog window will appear where you’ll have to choose the application name (Picture 1).

Picture 1 – Create new Facebook app window

Picture 1 – Create new Facebook app window

Facebook Java web application

Application name has to be unique. “App namespace” is used to access your application directly from Facebook domain so it is not important here because our application is deployed outside of Facebook. After you confirm it, application settings page will appear (Picture 2).

Picture 2 – Facebook application options screen

Picture 2 – Facebook application options screen

Here we can adjust various settings for the application we have created. We will use it only for “Website with Facebook Login” and that option needs to be checked. Under there we need to fill in the Site URL field. It is our application’s website URL from which we are authenticating to Facebook so we will put this: “http://localhost:8080”. The most important attributes to note here are App ID and App Secret at the top of the page. We have to write them down because we will use them as authentication parameters later.

In our login application page we’ll need some kind of button with the link that would have structure like this:

https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_REDIRECT_URI&scope=COMMA_SEPARATED_LIST_OF_PERMISSION_NAMES

Parameter client_id is App ID for the Facebook App we have created, redirect_uri is URI where the user will be redirected after authenticating on Facebook and scope is a permission list that we will ask from user to give to our application.

In our application we have used Java Server Faces so we will create JSF page with a button we can use to connect to Facebook. The page would look like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:p="http://primefaces.org/ui"
	xmlns:f="http://java.sun.com/jsf/core">
	<h:head>
	</h:head>
	<h:body>
		<h1>Login Page</h1>
		<h:form id="loginForm">
			<p:button value="Facebook Connect" href="#{loginPageCode.facebookUrlAuth}" />
			<br/><br/>
			<h:outputText value="#{loginPageCode.userFromSession}"></h:outputText>
		</h:form>
	</h:body>
</html>

You can see that we are using one ManagedBean with the name “loginPageCode”. The bean is used only to return the authentication link with all the parameters and some basic user data from session after user authenticates application on Facebook. It looks like this:

@ManagedBean (name ="loginPageCode")
@SessionScoped
public class LoginPageCode implements Serializable {
	private static final long serialVersionUID = -1611162265998907599L;

	public String getFacebookUrlAuth() {
		HttpSession session =
		(HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
		String sessionId = session.getId();
		String appId = "431631200204072";
		String redirectUrl = "http://localhost:8080/index.sec";
		String returnValue = "https://www.facebook.com/dialog/oauth?client_id="
				+ appId + "&redirect_uri=" + redirectUrl
				+ "&scope=email,user_birthday&state=" + sessionId;
		return returnValue;
	}

	public String getUserFromSession() {
		HttpSession session =
		(HttpSession) FacesContext.getCurrentInstance().getExternalContext().getSession(false);
		String userName = (String) session.getAttribute("FACEBOOK_USER");
		if (userName != null) {
			return "Hello " + userName;
		}
		else {
			return "";
		}
	}
}

The method getFacebookUrlAuth()is returning link that will redirect user to Facebook where, after logging in, the user will be redirected to authentication window for our Facebook application with all the permissions that we are asking (Picture 3). Note that the user needs to authenticate application only the first time.

Picture 3 – Facebook application authentication dialogue

Picture 3 – Facebook application authentication dialogue

If the user clicks “Go to App”, he is being redirected to URL which we have provided as a parameter, in this case "http://localhost:8080/index.sec". We are redirecting him to index.sec page because we will implement a servlet with “*.sec” pattern. Here is an example of that servlet named SecurityServlet:

@WebServlet("*.sec")
public class SecurityServlet extends HttpServlet {

	private static final long serialVersionUID = 8071426090770097330L;

	public SecurityServlet() {
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doPost(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		HttpSession httpSession = request.getSession();
		String faceCode = request.getParameter("code");
		String state = request.getParameter("state");
		String accessToken = getFacebookAccessToken(faceCode);
		String email = getUserMailAddressFromJsonResponse(accessToken, httpSession);
		String sessionID = httpSession.getId();
		if (state.equals(sessionID)){
			try {
				//do some specific user data operation like saving to DB or login user
				request.login(email, "somedefaultpassword");
			} catch (Exception e) {
				e.printStackTrace();
				response.sendRedirect(request.getContextPath() +"/facebookConnectError.jsf");
				return;
			}
			response.sendRedirect(request.getContextPath() +"/login.jsf");
		} else {
			System.err.println("CSRF protection validation");
		}
	}

	private String getFacebookAccessToken(String faceCode){
		String token = null;
		if (faceCode != null && ! "".equals(faceCode)) {
			String appId = "431631200204072";
			String redirectUrl = "http://localhost:8080/index.sec";
			String faceAppSecret = "7f43f0ce85285349e75bec6170ea960f";
			String newUrl = "https://graph.facebook.com/oauth/access_token?client_id="
					+ appId + "&redirect_uri=" + redirectUrl + "&client_secret="
					+ faceAppSecret + "&code=" + faceCode;
			HttpClient httpclient = new DefaultHttpClient();
			try {
				HttpGet httpget = new HttpGet(newUrl);
				ResponseHandler<String> responseHandler = new BasicResponseHandler();
				String responseBody = httpclient.execute(httpget, responseHandler);
				token = StringUtils.removeEnd
						(StringUtils.removeStart(responseBody, "access_token="),
                                                 "&expires=5180795");
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				httpclient.getConnectionManager().shutdown();
			}
		}
		return token;
	}

	private String getUserMailAddressFromJsonResponse(String accessToken,
             HttpSession httpSession) {
		String email = null;
		HttpClient httpclient = new DefaultHttpClient();
		try {
			if (accessToken != null && ! "".equals(accessToken)) {
				String newUrl = "https://graph.facebook.com/me?access_token=" + accessToken;
				httpclient = new DefaultHttpClient();
				HttpGet httpget = new HttpGet(newUrl);
				System.out.println("Get info from face --> executing request: "
                                  + httpget.getURI());
				ResponseHandler<String> responseHandler = new BasicResponseHandler();
				String responseBody = httpclient.execute(httpget, responseHandler);
				JSONObject json = (JSONObject)JSONSerializer.toJSON(responseBody);
				String facebookId = json.getString("id");
				String firstName = json.getString("first_name");
				String lastName = json.getString("last_name");
				email= json.getString("email");
				//put user data in session
				httpSession.setAttribute("FACEBOOK_USER", firstName+" "
						+lastName+", facebookId:" + facebookId);

			} else {
				System.err.println("Token for facebook is null");
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			httpclient.getConnectionManager().shutdown();
		}
		return email;
	}
}

Facebook authentication

Every request for a resource with a “.sec” extension in our web application will be collected by our SecurityServlet. In our servlet’s doPost() method we can see that we are first extracting “code” parameter from incoming request. This parameter was filled in by Facebook. Then we are using it to make a new request to Facebook to gain access_token which we need to make a request for user data (Picture 4).

Picture 4 - Sequence diagram for Facebook data access

Picture 4 - Sequence diagram for Facebook data access

Note that the user data is always received from Facebook in JSONObject so we need to extract textual data from JSON in order to use it. After we extract user data in this example, we’ll redirect the user’s browser to login.jsf page again but this time user data is read from session within our ManagedBean LoginPageCode(Picture 5).

Picture 5 - Example login page preview

Picture 5 - Example login page preview

Conclusion:

In this article we have shown you a simple way of integrating web applications with Facebook in the way of reading basic user data which can then be used to authenticate the user in our Java application. Note that this is just one way of implementing it and its purpose is to show basic Facebook security mechanisms. Also, there are a number of other interactions with Facebook that can be done (accessing extended user data, posting on behalf of the user, accessing user photos, etc.) but are out of the scope of this article. It should also be mentioned that ADF KickStart comes with modules that enable Facebook application integration (more on ADF KickStart components and usage read here)

References:

http://developers.facebook.com/docs/opengraph/tutorial/

http://developers.facebook.com/docs/authentication/server-side/

http://developers.facebook.com/docs/reference/api/

Project folder containing the source code for this example

17 comments on “Facebook user authentication in Java web application

  1. OakNinja on said:

    OMG i can only say thank you – skimming through this article and from what i’ve seen so far, this is the foundation of what i’ve been looking for sporadically for months!

    Regards!

  2. Rakesh Bhatt on said:

    Thank’s for this post! What about logging out a user after logged in I didn’t see any code for that

    • Hi Rakesh!
      For logging out user you can simply call invalidate method on session (session.invalidate()) to destroy your local session with current user. Note that session does not exist between your application and Facebook, you are just accessing their API.

  3. uday on said:

    Hi, Can you please provide the complete package to deploy and test the application.It is very difficult to know what jars you have used in this sample application

    Thanks and Regards
    Uday

      • uday on said:

        HI,

        Thanks for providing the package. Can this sample can be used for all oAuth server implemented providers like google,GitHub etc ?

        We also want to implement server side oauth impementation like facebook and google. Can you guide us how this can be implemented or provide us the sample.

        Thanks and Regards
        Uday

    • Hi,
      Project folder has been added to References section so you can see source code there.
      You can use any java web technology, I used JSF because it is in my opinion easiest cause you can simply define backing beans.
      Also request.login(email, “somedefaultpassword”) is just an example that illustrates some action you want to do with information about user acquired from Facebook. You cannot use request.login() method without providing password validation realm and that security mechanisms are out of scope of this example, please consult documentation on more info http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String, java.lang.String)

  4. Che on said:

    Hi! Is there any way you could get the user’s details? Like birthday, gender and email?

    Thanks in advance!

  5. Che on said:

    Hi!

    This is a bit off topic. but would you know how to
    “share” a page link on facebook without using User Interface? meaning it is on the back end only. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>