FaceBook authentication using Java

Bookmark/Share » Post FaceBook authentication using Java to digg. bookmark on del.cio.us Add TheLiveWeb.net to Technorati. add to stumbleupon Post FaceBook authentication using Java to Reddit Google Bookmark

Faecbook Looking around on the web, it seems the biggest hurdle that people face while writing a Facebook application in java is getting the authentication piece to work. There are some blogs where the solutions have been posted, and that would work. However, I noticed that they recommend using login servlet url as the callback url so that all the requests pass through that servlet before your custom logic routes the requests to the desired servlet based on url. That would sure work, but it looks like a hack (or at least not elegant)! More so, because servlet spec already comes with something that helps us intercept all the requests. Yes, I am talking about Servlet Filters which really makes it clean, and easy.

You can configure a servlet filter that intercepts all the requests, makes sure that user is logged in (or else redirects user to login page) before letting the request flow to your servlet that will serve this request. The application code can rest assured that the user has logged in, or else the request won’t reach it!

I spent some time writing the servlet filter and the authentication class which I thought would make sense to share. You can download the source code using the link at the end of this post. Here is a brief description of how it works.

The doFilter method of FaceBookAuthFilter simply delegates authentication verification to FaceBookAuthHandler class and accordingly let’s the user in, or redirects to login page:

public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
    HttpServletRequest httpReq =
            (HttpServletRequest) request;
    HttpServletResponse httpRes =
            (HttpServletResponse) response;
    try {
      FacebookRestClient authClient =
      FaceBookAuthHandler.getAuthenticatedClient(
                 httpReq, _apiKey, _secretKey);
      request.setAttribute(
                 "auth.client", authClient);
      chain.doFilter(request, response);
    } catch (FailedLoginException fle) {       

    //user not logged in
    forceLogin(httpRes);
} catch (Exception e) {
//handle exception
}       

}

Once the request reaches the application (which implies user is already logged in), you can just get the FaceBookRestClient from request object and use it as follows:

FaceBookRestClient client=(FaceBookRestClient)
       request.getAttribute("auth.client");
client.friends_get();//and so on

In order to configure the filter, you’d need to add the following to the web.xml

<web-app>
<display-name>
  Facebook Application
</display-name>
<filter>       

<filter-name>
 FaceBookAuthFilter
</filter-name>       

<filter-class>
 net.theliveweb.facebook.FaceBookAuthFilter
</filter-class>       

<init-param>
  <param-name>api_key</param-name>
  <param-value>[api-key]</param-value>
</init-param>
<init-param>
  <param-name>secret_key</param-name>
  <param-value>[secret-key]</param-value>
</init-param>
</filter>
<filter-mapping>
  <filter-name>FaceBookAuthFilter</filter-name>
  <url-pattern>*.do</url-pattern>
</filter-mapping>       

</web-app>

You will need to make the following changes to the web.xml:

  • Replace the api-key and secret-key
  • Change the url-pattern from *.do to the one that you use in your app

And you should be all set!

Following are the two classes that you can download:

  • FaceBookAuthFilter : The http servlet filter for intercepting user requests
  • FaceBookAuthHandler : Class used to verify authentication. Can also be used stand alone.

You can download the source code here.

[Click here for the basics of Facebook development platform, and how to get a simple application working]

If you liked this post or find this website useful, please consider subscribing to the full feed RSS. You can also subscribe by Email and have new posts sent directly to you.
Share » Post FaceBook authentication using Java to digg. bookmark on del.cio.us Add TheLiveWeb.net to Technorati. add to stumbleupon Post FaceBook authentication using Java to Reddit Google Bookmark

Next Steps »

21 Responses to “FaceBook authentication using Java”

  1. [...] [Update: If you’re writing the app in java, check this out] [...]

  2. i found an error in your source code…. before returning the client you are asking for a session id using

    fbClient.auth_getSession(authToken);

    you are not using it at all… also you haven’t checked if authToken is null , if it is it throws a null pointer exception…

    by the way thanks for the code… really clean job…

  3. Thanks Juan. The code checks for authToken not being null :

    if (sessionKey != null) {
    	...
    } else  if (authToken != null) {
    	...
    } else {
    	throw new FailedLoginException(...);
    }
    

    if neither sessionKey nor authToken are found, it throws FailedLoginException which the caller should catch and send the user to login page. Which line in the code threw NullPointerException? Let me know if you’re still getting the error so that I can fix it if needed. Thanks.

  4. Juan is referring to line 29 in FaceBookAuthHandler.java
    You invoke fbClient.auth_getSession(authToken) without checking if authToken is null (it can be) and regardless of the sessionKey being already provided. You also don’t do anything with the returned value.
    Still, great post, Java documentation on the Facebook API is very lacking and I personally thank you for trying to fill the gaps.

  5. Thanks Javier. It should be fixed now - that line was anyway redundant since the session key is obtained from the request parameter.

  6. Great post !

    However, I’ve got a few newbie questions :

    - it looks like the filter instanciates a new client upon each request, but when your application has multiple “configuration” pages in canvas, each one being called from a link like edit.jsp,delete.jsp, etc. , couldn’t a client be instead stored in a request.getSession() and retrieved later on ? I fear multiple clients creation could be cpu consuming.

    - maybe you could commit this filter code to http://code.google.com/p/facebook-java-api/ , with a new web.xml init param defining which type of client is to be created, REST, JSON or JAXB ? (disclaimer: I’m not the project owner)

    - there is a really minor “typo” in your web.xml, needs a breakline to indent nicely (yes, I’m nitpicking :D)

  7. Thanks Laurent for the comments. Your suggestions are completely valid - the reason I didn’t show storing the facebook client in http session was that in this post I wanted to mainly emphasize on use of filter to do the authentication and keep it simple. Once you have this working, you can add the code to cache facebook client in session. Or if people want it, I can add that part to the sample code.

    I am also thinking of posting an example using the facebook api on code.google.com when time permits.

    Thanks again for suggestions!

  8. Thanks for the helpful information. I noticed a couple of things and was curious if you noticed similar behavior.

    One, I noticed that an earlier post had mentioned removing the following piece of code:

    fbClient.auth_getSession(authToken);

    However, it was my experience that this was necessary because with this code removed, I would get errors returned from FaceBook stating that the session was no longer valid. I would agree, that this doesn’t really make sense, but that was my observation.

    Second, I tried save the ‘auth client’ in the HttpSession instead of the Request and was unsuccessful. When looking at the stack trace it would appear there was some sort of ‘null pointer exception’ that was eventually described as a jasper exception. Unfortunately, I couldn’t get much more information and eventually abandoned trying to store this in the session … which would of course be much more efficient.

    If you have noticed the similar behavior these observations, I would be interested.

  9. Thanks Darin. I think the “session not valid” problem you referred to may occur when someone tries to access the app before logging into facebook. So I have added that line of code, but it gets executed only if authToken is not null so the NPE reported earlier does not occur.

  10. ok, sorry it took some time to get back with you.

    I’m embarrassed to say the problem was really on my side and some configuration issues. My Tomcat instance is running behind an Apache web server and I forgot to include ‘QSA’ on my rewrite rules when forwarding the requests to my Facebook application. This was then complicated by the fact that my JSP pages (at least the underlying .java files) were not being rebuilt when I was making changes to the JSP pages. But, I’ve now fixed these problems and can report that everything is working nicely … even when setting the auth variable as a session variable as opposed to a request variable.

    Thanks again for your contribution as this really helped clarify how one could perform Facebook authentication within a Java (J2EE) environment.

  11. Thanks Darin for posting back your findings. Great to know that it worked for you!

  12. Laurent Perez on January 3rd, 2008 at 7:03 am

    Hi

    I’m not sure this is a bug or not, but within forceLogin(res), you use a sendRedirect directive.

    This can’t work if your app is a canvas one, instead, you should getWriter().println() fbml fb:redirect markup, or some a href link to the login url, appending “&canvas” at the end.

  13. Laurent, I spent HOURS trying to figure out why response.sendRedirect wasn’t working. Thanks so much for the fbml fb:redirect dealio, it did the trick.

    private void forceAppAdd(HttpServletResponse response) throws IOException {
    PrintWriter out = response.getWriter();
    String redirectPage = “http://www.facebook.com/add.php?api_key=” + _apiKey;
    out.println(”");
    }

    =)

  14. Ack, the above post came out a bit funky.. basically where the HERE is in out.println(”HERE”), replace HERE with the fb:redirect markup. It works then.

  15. hi liveweb

    when i have used response.sendRedirect() i was getting the error

    illegal tag “meta” under “fb:canvas” ,But when i replaced with fb:redirect that error was not coming but the intended page was not coming in the facebook rightside frame but it was occupying the whole page .
    any idea why that is happening

  16. Laurent - by Canvas page you mean FBML application, as opposed to iFrame application? Because you get this error in iFrame as well.

  17. are the revised version of the above updates to the filter including this:

    private void forceAppAdd(HttpServletResponse response) throws IOException {
    PrintWriter out = response.getWriter();
    String redirectPage = “http://www.facebook.com/add.php?api_key=” + _apiKey;
    out.println(””);
    }

    added to the jar?

  18. Regarding redirecting properly when you’re inside an iframe or standalone, the facebook-java-api project on Google Code* has a Companion Utility** that does the redirect properly. I haven’t used it yet and don’t know whether it’ll work properly from a filter, so YMMV.

    * http://code.google.com/p/facebook-java-api/
    ** http://64.81.51.104:54321/facebook/helper/javadoc/index.html

  19. [...] you’re writing your application in Java, TheLiveWeb has a free servlet filter that takes care of checking a user’s login state for you. Their [...]

  20. Hi there,

    Firstly thank you for the very useful code! This has helped me get off the ground!

    The only problem I have is when I send a redirect to the user if they are not logged in because my app is within an iFrame the log in page almost reproduces another instance within my iFrame so I have the outer Facebook container with my iFrame and then the iFrame container with the facebook authentication? does that make sense?

    I’m guessing not

  21. If you use the latest code form the google facebook-java-api, then here’s the latest way to do authentication:

    public class ControllerServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {
    private static final Logger LOG = Logger.getLogger(ControllerServlet.class);

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    LOG.info(”doGet was called”);
    processRequest(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    LOG.info(”doPost was called”);
    processRequest(request, response);
    }

    private void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    FacebookRestClient client = authenticate(request, response);

    if (client != null) {
    if (getFacebookInfo(request, client)) {
    LOG.info(”about to render the main page jsp”);
    request.getRequestDispatcher(”/content/jsp/facebook/main_page.jsp”).forward(request, response);
    }
    }
    }

    private FacebookRestClient authenticate(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Facebook fb = new Facebook(request, response, Constants.FB_API_KEY, Constants.FB_SECRET_KEY);
    FacebookRestClient client = null;

    String next = request.getServletPath().substring(1);

    if (fb.requireLogin(next)) {
    LOG.info(”facebook util is redirecting to login page…”);
    return null;
    }

    client = fb.getFacebookRestClient();

    if (client != null) {
    client.setIsDesktop(false);
    }

    return client;
    }
    }

Leave a Reply

Related Posts from the Past: