Implementing Facebook login (part 3)
Damn Facebook documentation! I finally managed to piece together a better picture - after first getting all that info in the previous posts (part 1, part 2) - about how registration and login can be handled.
Basically, you can't use the registration tool unless you really want to replace your registration dialog with Facebook's own version. You can't redirect to it conditionally, e.g. if the user has Facebook and clicks the login button, since the login will already trigger the Facebook authorization process.
So unless you want two logins (Facebook login link and regular login form) and two registration links (regular registration page and Facebook register page), you can't use the registration tool. My ideal implementation would just have a single link for everything related to Facebook, but present the full registration form if the user clicks it and has not yet registered with my site... no luck.
Hence, I will do this the traditional way:
- Use the Javascript SDK to render the Facebook Login link and popup.
- Ask for additional permissions on the Login.
- When the authorization returns, process the user login / registration.
- If the user wants to register using Facebook, then they will still need to fill in additional fields in a separate field after authorizing the information we can read from Facebook.
Preparations
Get an appid and a secret from Facebook. Register your website/app here to get an appid and secret. Add the Facebook namespace. Your HTML tag should contain the additional xmlns:fb -attribute so that the Facebook custom tags work with IE:html
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">
I did not know you could add XML namespaces to your documents and actually have custom tags which work in all current browsers, but since Facebook does it, it must have been tested well.
Rendering the Facebook login link and popup
[codesyntax lang="php"]html
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : '<?php echo $facebook->getAppId(); ?>',
session : <?php echo json_encode($session); ?>, // don't refetch the session when PHP already has it
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// whenever the user logs in, we tell our login service
FB.Event.subscribe('auth.login', function() {
window.location = "<?php echo URL::site('/user/fb_login') ?>";
});
};
(function() {
var e = document.createElement('script');
e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());
</script>
[/codesyntax]
Asking for additional permissions
You have to do this by adding the perms attribute to the fb:login-button tag. The links in the docs are broken, but here is the page documenting the login button and the extended permissions you can ask for are listed here. We'll just ask for the email address:html
<fb:login-button perms="email" size="large"></fb:login-button>
Processing the resulting login or registration
As you can see above, we subscribe to the auth.login event using Javascript and specify that on completion, the user will be redirected to /user/fb_login/. On that page, we need to:- Check whether a user account exists with the returned Facebook user id.
- If no user is found with the FB uid, retrieve the user's email via the Graph API and check whether a user exists with that email. If so, we will merge the user.
- If no user is found with the FB email, create a new account.
- If creating a new user fails, then accept defeat and show the regular registration page.
Logging out
We need to handle logging out sensibly. I prefer that the user explicitly clicks a login button if they do not currently have a session with our application. Automatic relogin is confusing, particularly when logging out usually redirects to the login page. So we need to handle the case where the person is connected (logged in to Facebook and authorized with us) by displaying a custom login button. You can find the Facebook logo from the branding site. Of course, a Google search for facebook logo won't find it, so click here to get the image that you are allowed to use for this purpose. ````js window.fbAsyncInit = function() { FB.init({ appId : '<?php echo Kohana::config('facebook')->app_id; ?>', status : true, // check login status cookie : true, // enable cookies to allow the server to access the session xfbml : true // parse XFBML }); // whenever the user logs in, we tell our login service FB.Event.subscribe('auth.login', function() { window.location = "<?php echo URL::site('/user/fb_login') ?>"; }); // if the user is already logged in, redirect them to the login action // they cannot reach the login page if they are already logged in // since login() redirects to profile if the user is logged in FB.getLoginStatus(function(response) { if (response.status == 'connected') { document.getElementById('fb-login-li').innerHTML = '<a href="<?php echo URL::site('/user/fb_login') ?>"><img src="/img/fb-login.png"></a>'; } else { document.getElementById('fb-login-li').innerHTML = '<fb:login-button perms="email" size="large"><?php echo ('Login / Register with Facebook')?></fb:login-button>'; FB.XFBML.parse(document.getElementById('fb-login-li')); } }); }; ````Appendix: all fb:login-button attributes
The Facebook documentation does not list the fb:login-button attributes, which is infuriating. I found a forum post (here), which documents the optional attributes of fb:login-button:- condition; string Indicates whether the button is visible or hidden.
- size; string Specifies the size of the button. Specify icon to display a favicon only, or small, medium, large, or xlarge. (Default value is medium.)
- autologoutlink; bool If true and the user is already connected and has a session, then the button image changes to indicate the user can log out. Clicking the button logs the user out of Facebook and all connected sessions. (Default value is false.)
- background; string Specifies the button image to use that is anti-aliased to match the background of your site -- whether it's pure white, light, or dark. Specify white, dark, or light. (Default value is light.) Note: You don't specify this attribute if you are using v="2".
Comments
Facebook Lead Gen: This series is great! I thank you for pointing out the fb:login-button attributes. :)
I'm currently developing a PHP script that allows email marketers to capture user details to a database through a Facebook button (http://fbleadgen.com) but I've bumped into a couple of hurdles along the way due to FB's (lack of) documentation!
Rishabh Tripathi: thank you very much for this article. can you point out the server side coding in Ruby on rails or give me some url where I can find it as I google it alot but havent found any good documentation.
Thanks in advance
Max: Nice tutorial, you helped me to catch more concepts. Expecially thanks to your graph images on lexons 1 n 2,
It would have been nice of u to post a zip with a complete running example.
In the 3rd lesson i guess u miss some steps to make it complete. For example u use some PHP class defines some where without telling how to include them in the code... Kohana::config('facebook'), or PHP::url...
Anyway this is definitely a positive comment ...thanks
Mikito Takada: Yeah, I kind of ran out of time to write a tutorial covering 100% of the details; you should look at the code in my Kohana auth module for a complete working implementation with all the details worked out; covering every step would probably double the length of the post.
Specifically, see action_fb_login in (last function in the file): https://github.com/mixu/useradmin/blob/master/modules/user/classes/controller/useradmin/user.php
and https://github.com/mixu/useradmin/blob/master/modules/user/views/user/login.php
Note that the $facebook is just an instance from Facebook's PHP SDK.
DD: Can you explain how to implement it with registration-url?
Comprar Acciones: I'm trying to follow the instructions in this post but I can not register the website for a app_id. When I enter my username and password in facebook, facebook tells me that my user or password are not valid. Why?.
r0h1: Well I'm a bit confused, after this part 3. It seems that part 2 is not valid any more, or I did not understand correctly? Let's take foursquare facebook login as example: They have 2 separate sign up processes, one for fb (using the Javascript SDK) and the internal one.
- If you register with the fb login button (javascript sdk), on next page you need to fill email and password so it will create an internal 4sq account - connected to your fb one. Then, every time you login through fb button, the fb authentication will be taken as "valid" by 4sq, without requiring any other input. So at this point, all we need to do is managing the response cookie? Can you please explain how to do that, or link from fb documentation? Cause I cannot find it....
Andrew: Thanks, this worked for me!
Rajeev Jha: Hi Mixu I have found your post to be useful during my research. I have created a post about serve side implementation here :- http://rjha94.blogspot.in/2012/02/how-to-integrate-facebook-login-with.html
I have added robust error handling (even facebook sample has error suppressing operators) and a nice working example. Thanks