In part 2 of my Facebook login tutorial, I will discuss implementing Facebook registration (see also: part 1 and part 3).

My design goals are to allow users to have either their own, separate account on the site or to link their account with Facebook. The design goals are:

  • User registration

    • Allow the user to register using Facebook and retrieve data from their profile to help fill in their information.
    • Allow the user to register without using Facebook.
    • Allow the user to add a Facebook profile later on to their account.
    • Treat Facebook user ids just like email addresses: allow just one user account associated per Facebook user ID.
  • User login / authentication

    • Allow the user to sign in with just clicking a Sign in via Facebook button.
    • Allow the user to sign in using their registered account name, if they have one.

Registration flow

Facebook has recently (Dec 16th 2010) launched a registration tool for streamlining Facebook-based registration. We will be using it to implement the Facebook-enabled registration. However, since the dialog looks very "facebooky", and some users will prefer not to have anything to do with Facebook, we will also offer our own registration form which looks more consistent with the site, but has no Facebook stuff in it.

The following diagram illustrates the registration flow with the Facebook alternative:

So basically, on the Login page, we will show a Facebook login link next to the regular login form, as well as normal registration link. If the user clicks the Facebook login link, then they will either be signed on via Facebook, or if they haven't signed up, they will be shown the Facebook enabled registration page. If the user clicks the regular registration link, they will be shown the non-Facebook registration page. Finally, the user can just login using their username and password on your site using the regular login form.

Designing the Facebook-enabled registration page

If you already have a registration system on your site, you can leave that there. You then need to add the secondary, Facebook-enabled registration page.

The Facebook registration just needs to contain an iframe with the following content:

<iframe src="http://www.facebook.com/plugins/registration.php?
             client_id=YOUR_APP_ID&
             redirect_uri=URLESCAPED_RETURN_PAGE
             fields=name,email"
        scrolling="auto"
        frameborder="no"
        style="border:none"
        allowTransparency="true"
        width="100%"
        height="310px">
</iframe>

Check out the Facebook documentation on what you can put in the fields. The new registration tool can support custom fields. I will assume here that you just want their name and email.

Receiving the data from the Facebook registration form

As you will notice from the Facebook documentation, the return value of the Facebook registration form is base64-encoded JSON, which includes an encoded (H)MAC (message authentication code) which is separated from the data itself by a single dot character.

First split the string, then decode the data (from Facebook's example code):

<?php
  // split to two variables based on the first dot character
  list($encoded_sig, $payload) = explode('.', $signed_request, 2);
  // decode the data
  $sig = base64_url_decode($encoded_sig);
  $data = json_decode(base64_url_decode($payload), true);

  echo 'Hello '.$data['registration']['name'].'!';
  echo 'Your Facebook user ID is '.$data['user_id'].'.';

You should also authenticate the return value using the secret key you received when you registered your website with Facebook. Otherwise, someone could fake a registration request and cause problems with user login. You can do it like this:

<?php
  // check the signature in $sig using $payload
  if ($sig !== hash_hmac('sha256', $payload, FACEBOOK_SECRET, TRUE)) {
    // INVALID SIGNATURE! Show an error message.
  }

Saving the data into an existing user account system

There are number of things you want to take into account when saving the from the user data into the system:

  • Facebook does not give you a username for the user unless you ask for one. You can either:

    • Ask for one from the user as a custom field (easy, but I don't like it since it reduces the convenience of Facebook integration; and what about if that username is taken?).
    • Make it so that you can have user accounts that do not have a username at all.
    • In both cases, you have to make sure that the user cannot log in directly using the old style login, only via Facebook (unless you ask for a password as well).
  • The user might have already registered an account on your site with the same email address. In this case, you don't want to duplicate the user, and usually you can't since email addresses are expected to be unique across the system.
  • You need to make database changes to add two pieces of information: first, the user's Facebook user id and second, the time-limited access token we need to retrieve more data from Facebook (oauth_token in the return value).
Since these are specific to your application, I can't say much about them. In any case, you want to add facebook_user_id as one field in the user information.

Option 1 would be to set the user name to empty for those users registered from Facebook. You then need to design your application so that it can show the full name of the user instead of the username elsewhere, since this field will now not necessarily be filled in. A properly designed app should not need to search for users by their username, but rather by user ID on your site. You also need to make sure that users with empty usernames/passwords cannot log in.

Option 2 would be to auto-generate a user id for the user based on their name. You need to make sure the username is not taken, and if it is, generate an alternative. Then you can allow the user to change their username later, as long as uniqueness checks are maintained. You need to make sure that users without a password cannot log in, or generate a really long random string as the password, hash it and forget the password completely.

Option 3 would be to ask for a username, and perhaps even a password - but then the only benefit is that you get some information typed in automatically, which does not make for a smooth experience (weren't we trying to avoid filling in fields here?).

I would go with option 2. While it does theoretically open the possibility that someone could guess the random string and autogenerated user id; I think there are easier avenues of attack such as guessing weak passwords.

Next part

In part 3 of my Facebook login tutorial I go into implementation specifics using the Javascript SDK.

Comments

Kabindra Bakey: just the thing i need... its better with the logout system flowchart embeded too