Spring Security & Facebook OAuth 2.0 Integration with Graph API

11,133

Solution 1

Here's an MVC implementation of facebook OAuth 2.0 The code's in C# and hopefully its similarity with java helps you out.

Controller(Entry point):Controller(in MVC) is the point in the code where the control reaches after someone clicks on the login link.

 public ActionResult Authenticate()
        {
                var oauthFacebook = new FacebookOAuth();
                if (Request["code"] == null)
                {
                    //Redirect the user to Facebook for authorization.
                    Response.Redirect(oauthFacebook.AuthorizationLinkGet());
                }
                else
                {
                    //Get the access token and secret.
                    oauthFacebook.AccessTokenGet(Request["code"]);
                    if (oauthFacebook.Token.Length > 0)
                    {
                        //We can now make our api calls
                        var user = oauthFacebook.GetAttributes();
                    }
                }
        }

FacebookOAuth Class

public class FacebookOAuth : Oauth
    {
        public FacebookOAuth()
        {
            Authorize = "https://graph.facebook.com/oauth/authorize";
            AccessToken = "https://graph.facebook.com/oauth/access_token";
            CallbackUrl = "http://<YourURLHere>/Authenticate";
            AttributesBaseUrl = "https://graph.facebook.com/me/?access_token=";
            ConsumerKey = ConfigurationManager.AppSettings["FacebookConsumerKey"];//Ur Consumer Key goes here
            ConsumerSecret = ConfigurationManager.AppSettings["FacebookConsumerSecret"];//Ur Consumer secret goes here
            Provider = "Facebook";
        }

        public override string AuthorizationLinkGet()
        {
            return
                string.Format(
                    "{0}?client_id={1}&redirect_uri={2}&scope=email,user_education_history,user_location,user_hometown",
                    Authorize, ConsumerKey, CallbackUrl);
        }

        public User GetAttributes()
        {
            string attributesUrl = string.Format("{0}{1}", AttributesBaseUrl, Token);
            string attributes = WebRequest(Method.Get, attributesUrl, String.Empty);
            var FacebookUser = new JavaScriptSerializer().Deserialize<FacebookUser>(attributes);
            return new User()
            {
                FirstName = FacebookUser.first_name,
                MiddleName = FacebookUser.middle_name,
                LastName = FacebookUser.last_name,
                Locale = FacebookUser.locale,
                UserEmail = FacebookUser.email,
                AuthProvider = Provider,
                AuthToken=Token
            };
        }
    }

OAuth baseclass(Class from which FacebookOAuth derives)

  public abstract class Oauth
    {
        #region Method enum

        public enum Method
        {
            Get,
            Post,
            Delete
        } ;

        #endregion

        protected string AccessToken;
        protected string AttributesBaseUrl;
        protected string Authorize;
        protected string CallbackUrl;
        protected string ConsumerKey;
        protected string ConsumerSecret;
        public string Provider { get; protected set; }

        public string Token { get; set; }

        public virtual string AuthorizationLinkGet()
        {
            return
                string.Format(
                    "{0}?client_id={1}&redirect_uri={2}&scope=publish_stream,email,user_education_history,user_location",
                    Authorize, ConsumerKey, CallbackUrl);
        }

        public void AccessTokenGet(string authToken)
        {
            Token = authToken;
            string accessTokenUrl = string.Format("{0}?client_id={1}&redirect_uri={2}&client_secret={3}&code={4}",
                                                  AccessToken, ConsumerKey, CallbackUrl, ConsumerSecret, authToken);
            string response = WebRequest(Method.Get, accessTokenUrl, String.Empty);

            if (response.Length > 0)
            {
                //Store the returned access_token
                NameValueCollection qs = HttpUtility.ParseQueryString(response);

                if (qs["access_token"] != null)
                {
                    Token = qs["access_token"];
                }
            }
        }

        public string WebRequest(Method method, string url, string postData)
        {
            StreamWriter requestWriter;
            string responseData = string.Empty;

            var webRequest = System.Net.WebRequest.Create(url) as HttpWebRequest;
            if (webRequest != null)
            {
                webRequest.Method = method.ToString();
                webRequest.ServicePoint.Expect100Continue = false;
                webRequest.Timeout = 20000;

                if (method == Method.Post)
                {
                    webRequest.ContentType = "application/x-www-form-urlencoded";
                    //POST the data.
                    requestWriter = new StreamWriter(webRequest.GetRequestStream());
                    try
                    {
                        requestWriter.Write(postData);
                    }

                    finally
                    {
                        requestWriter.Close();
                    }
                }
                responseData = WebResponseGet(webRequest);
            }
            return responseData;
        }

        public string WebResponseGet(HttpWebRequest webRequest)
        {
            StreamReader responseReader = null;
            string responseData;
            try
            {
                responseReader = new StreamReader(webRequest.GetResponse().GetResponseStream());
                responseData = responseReader.ReadToEnd();
            }
            finally
            {
                if (webRequest != null) webRequest.GetResponse().GetResponseStream().Close();
                if (responseReader != null) responseReader.Close();
            }
            return responseData;
        }
    }

Solution 2

I actually just finished my non-javascript, implementation of the Facebook Graph API Authentication last night. I was a gargantuan pain in the a**, but it works and it's working fairly well.

I used the example from the link you posted above as a starting point, as well as, the code from here as a starting point. I had to write my own implementation of their FacebookGraphAuthenticationProvider and their FacebookGraphAuthenticationFilter, but now it works the way I want it to.

You need to create implementations of both of these files, put your filter in the filter chain, and create a implementation of the Spring Security UserDetailsService that the Provider can use to manage your user account information. I have some code on my machine at home that I can send you via email if you like.

Here are the steps I had to use to get the authentication to work:

  1. Get an "code" for a user, this is done by making the following call: https://www.facebook.com/dialog/oauth?client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&scope=email,read_stream (The scope is all the permissions you want to request from FB). This call will create an "authentication code" which will then be sent back to your "redirect_uri" (which I stated as http://{my fb app registered domain}/j_spring_security_authentication_check.

  2. Once you have this "code", you need to make a call within your AuthenticationProvider that will retrieve an access_token for your user's session: this URL looks like: https://graph.facebook.com/oauth/access_token? client_id=YOUR_APP_ID&redirect_uri=YOUR_URL&client_secret=YOUR_APP_SECRET&code=THE_CODE_FROM_ABOVE. You have to make sure your "redirect_uri" is the same as the one you did in #1. You'll make the above call using something like Apache's HttpClient, or the like.

  3. Now with this access_token (which comes in the body of above response), you can get your user's profile information with the following URL: https://graph.facebook.com/me?access_token={ACCESS_TOKEN from above). The response will be in JSON. You can also use the access_token with all of the graph API to post status, pictures, etc.

I have some code at home that has my full implementation that I would be happy to share.

I hope this helps at least a bit. I suggest using the Spring Social app to get started with posting status, pictures, wall stuff, etc. This will be a good place to start looking at FB-Spring interaction.

Share:
11,133
MatBanik
Author by

MatBanik

Updated on June 16, 2022

Comments

  • MatBanik
    MatBanik almost 2 years

    Please, at least pseudo (but from working environment not "maybe this should work") application context and controller/filter that will authenticate and/or auto-register Facebook users.

    This link: http://blog.kadirpekel.com/2009/11/09/facebook-connect-integration-with-spring-security/ will not do. Actually I will put minus point to anyone who will post it as answer. I spend 2 hours with the thing and I didn't get it to work. I ended bit more bolder and feeling more stupid than usual after this endeavor :-(

    I would really like to see OAuth 2.0 solution for facebook connect. And restrict the use of Facebook JavaScript API to absolute minimum.

    Following link shows about what I need: http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/

    Please post only code to this question. I already got all the advice I can handle.

    UPDATE

    I have servlet solution and posted answer here if anyone is interested: Facebook Connect example in JSP (tomcat)

  • Brad
    Brad about 13 years
    Mulki, the current spec shows the access token response being json. Your implementation shows it coming back as a querystring parameter. Is that just a difference between the spec and facebook's implementation ?
  • Picflight
    Picflight about 12 years
    Mulki, is this method considered OAuth 2? Can I use similar process to get users authenticated via FB?
  • Daniel Robertus
    Daniel Robertus almost 10 years
    Hi.. i have some problem... can you email me some example from your code please?? i want to integrate my existing authentication (with spring security) with Facebook Connect (or Login).. If u dont mind, email me at [email protected]
  • El Guapo
    El Guapo almost 10 years
    Hi Daniel... unfortunately this project is long gone :( If you have some specific questions I'll be happy to answer them...
  • Daniel Robertus
    Daniel Robertus almost 10 years
    Thanks for replying.. if you dont mind, Please visit my question stackoverflow.com/questions/23440141/…