How to Authenticate Users With Facebook Connect

How to Authenticate Users With Facebook Connect

Tutorial Details
  • Difficulty: Intermediate
  • Completion Time: 45 Minutes

Lately, there’s been quite a fuzz about lazy registration. It turns out that the less the user has to think, the higher the conversion rates are! What a thought! If everybody seems to have a Facebook profile, why not add a one-click user registration? I’ll show you how to do that today.


Step 1. The Setup

MySQL Table

Let’s begin by creating a database table.

CREATE TABLE `users` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
    `oauth_provider` varchar(10),
    `oauth_uid` text,
    `username` text,
    PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1;

Quite simple: we will be setting up a table for user information with id, username, first and last name, the URL to the user’s picture, and registered date. Also, we’re adding both an oauth_provider and oauth_uid fields, to distinguish between different third party open authentication protocols and their identifiers. For example, let’s say that, next week, you decide that it’s a good idea to also let Twitter users in. Easy; you just set another value to the oauthprovider, and avoid duplicating oauthuid values.

The Facebook App

Let’s begin by creating a new application. Give it a name and agree to the terms and conditions. Next, grab both the API Key and Secret in the basic tab as shown below.

On the canvas tab, set both the Canvas URL and Post-Authorize Redirect URL to your localhost and path that the script will process — something like http://localhost.com/login_facebook.php?. Note the question mark at the end and the domain; both are required by Facebook. Simply set your hosts file to a valid domain name.

On the connect tab, set the Connect URL to the same value and set localhost.com (or the one you are using) as the Base Domain.

Now save, download the client library, and unzip facebook.php in the srcdir to a new directory created in the root.


Step 2. The Callback

The authentication flow has three steps:

  1. The local script generates a URL asking the user for permission
  2. Facebook returns to the Canvas URL specified with a GET parameter
  3. The GET parameter authenticates the session

Let’s make a quick test before registering and login.

# We require the library
require("facebook.php");

# Creating the facebook object
$facebook = new Facebook(array(
    'appId'  => 'YOUR_APP_ID',
    'secret' => 'YOUR_APP_SECRET',
    'cookie' => true
));

# Let's see if we have an active session
$session = $facebook->getSession();

if(!empty($session)) {
    # Active session, let's try getting the user id (getUser()) and user info (api->('/me'))
    try{
        $uid = $facebook->getUser();
        $user = $facebook->api('/me');
    } catch (Exception $e){}

    if(!empty($user)){
        # User info ok? Let's print it (Here we will be adding the login and registering routines)
        print_r($user);
    } else {
        # For testing purposes, if there was an error, let's kill the script
        die("There was an error.");
    }
} else {
    # There's no active session, let's generate one
    $login_url = $facebook->getLoginUrl();
    header("Location: ".$login_url);
}

Now, go to http://localhost.com/login_facebook.php, and let’s see what happens. If you are redirected to Facebook and requested for permission, we are on the right track.

However, there might be two issues. The first one: if you’re redirected to Facebook, but it shows an error, there might be a missing value in the configuration. Go back to your application settings and check both the Connect and Canvas tabs and make sure the fields are ok as described above.

There might be another issue, where you see an error, like “Uncaught CurlException: 60: SSL certificate problem, verify that the CA cert is OK.” This happens because of the CURL settings. You’ll have to open facebook.php, find the makeRequest() method, and, inside the function, find this line:

$opts = self::$CURL_OPTS;

Immediately following it, add:

$opts[CURLOPT_SSL_VERIFYPEER] = false;

I hate hacking libraries, but I haven’t found another way. Well, let’s continue with user registration. I’ve also added a try/catch statement, because, if there’s an old session keys in the GET params in the URL, the script will die with a horrible error.


Step 3. Registration and Authentication

We’ll next be working with MySQL. Please note that I will not implement a data sanitizer, since I want to keep the code as short and on task as possible. Please keep this in mind: always sanitize your data.

First, let’s connect to the database.

mysql_connect('localhost', 'YOUR_USERNAME', 'YOUR_PASSWORD');
mysql_select_db('YOUR_DATABASE');

Now, let’s work on the $session conditional, in case we have a session.

# We have an active session; let's check if we've already registered the user
$query = mysql_query("SELECT * FROM users WHERE oauth_provider = 'facebook' AND oauth_uid = ". $user['id']);
$result = mysql_fetch_array($query);

# If not, let's add it to the database
if(empty($result)){
    $query = mysql_query("INSERT INTO users (oauth_provider, oauth_uid, username) VALUES ('facebook', {$user['id']}, '{$user['name']}')");
    $query = msyql_query("SELECT * FROM users WHERE id = " . mysql_insert_id());
    $result = mysql_fetch_array($query);
}

Note that I’m querying the database, looking for facebook as a oauth_provider; it’s generally a good idea, if you want to accept other OAuth providers (as twitter, Google Accounts, Open ID, etc.) and a oauth_uid, since it’s the identifier the provider gives to its user accounts.

The oauth_provider field could potentially lead to bad performance if we leave it as a text field type. As such, the best option is setting it to an ENUM type.

We have now a $result var with the values queried from the database. Let’s next add some sessions. Add this line at the beginning of your script.

session_start();

After the empty($result) conditional, append the following:

if(!empty($user)){
    # ...

    if(empty($result)){
        # ...
    }

    # let's set session values
    $_SESSION['id'] = $result['id'];
    $_SESSION['oauth_uid'] = $result['oauth_uid'];
    $_SESSION['oauth_provider'] = $result['oauth_provider'];
    $_SESSION['username'] = $result['username'];
}

As it makes little sense to authenticate a user who is already logged in, just below the session_start() line, add:

if(!empty($_SESSION)){
    header("Location: home.php");
}

And in the scripts which require authentication, just add:

session_start();
if(!empty($_SESSION)){
    header("Location: login_facebook.php");
}

And if you want to display the username, access it as an array.

echo 'Welcome ' . $_SESSION['username'];
# or..
echo 'Welcome ' . !empty($_SESSION) ? $_SESSION['username'] : 'guest';

Step 4. Additional Methods

Facebook has a ton of connect features, but here are four that I’ve found to be the most useful.

Legacy Methods

I might be missing something, but the FQL seems more flexible and easy than the Graph API. Fortunately, Facebook still lets developers use it, altough with the new library, it has changed a bit.

If you want the user id, first name, last name, squared thumbnail for the user picture, the biggest user picture available, and his or her gender, you can use the users.getInfo method.

    $uid = $facebook->getUser();
    $api_call = array(
        'method' => 'users.getinfo',
        'uids' => $uid,
        'fields' => 'uid, first_name, last_name, pic_square, pic_big, sex'
    );
    $users_getinfo = $facebook->api($api_call);

You can check the full list of fields available for Users.getInfo.

It is possible to achieve the same result, using FQL.

    $uid = $facebook->getUser();
    $fql_query  =   array(
        'method' => 'fql.query',
        'query' => 'SELECT uid, first_name, last_name, pic_square, pic_big, sex FROM user WHERE uid = ' . $uid
    );
    $fql_info = $facebook->api($fql_query);

Here’s the list of tables which can be accessed with FQL, as well as the fields available for the table users.

Extended Permissions

Facebook provides applications with some interaction with the user’s data – just as long as it’s authorized. With the old API, the authorization for additional permissions was exclusively available for the Javascript SDK (altough I’m not quite sure). With the new API, we can easily redirect the user to an authorization dialog in Facebook, and return to our site after the access is either granted or denied.

In the following example, we will be redirecting a user to authorize posts status updates, photos, videos and notes, the user’s real email address, birthday and access to photos and videos.

$uid = $facebook->getUser();

# req_perms is a comma separated list of the permissions needed
$url = $facebook->getLoginUrl(array(
    'req_perms' => 'email,user_birthday,status_update,publish_stream,user_photos,user_videos'
));
header("Location: {$url} ");

Here’s a full list of permissions. Note that you can specify both the url to direct to if the user accepts and the url to be redirected to if the user denies. The key for these array elements are next and cancel_url, respectively. Here’s a quick example:

$url = $facebook->getLoginUrl(array(
    'req_perms' => 'email',
    'next' => 'http://localhost.com/thanks.php',
    'cancel_url' => 'http://localhost.com/sorry.php'
));

If not specified, the default is the requesting script’s location.

Checking for Extended Permissions

Since the user can easily revoke permissions, the application should always check if a given permission is granted before using it, specially if it’s about publishing something. We will have to use the legacy API, as it seems it’s not fully implemented with the new one yet.

    $uid = $facebook->getUser();

    # users.hasAppPermission
    $api_call = array(
        'method' => 'users.hasAppPermission',
        'uid' => $uid,
        'ext_perm' => 'publish_stream'
    );
    $users_hasapppermission = $facebook->api($api_call);
    print_r($users_hasapppermission);

The ext_perm will only support the old list of available permissions.

Publishing to the Wall

Let’s post something to the wall after verifying the user has the publish_stream permission.

    # let's check if the user has granted access to posting in the wall
    $api_call = array(
        'method' => 'users.hasAppPermission',
        'uid' => $uid,
        'ext_perm' => 'publish_stream'
    );
    $can_post = $facebook->api($api_call);
    if($can_post){
        # post it!
        $facebook->api('/'.$uid.'/feed', 'post', array('message' => 'Saying hello from my Facebook app!'));
        echo 'Posted!';
    } else {
        die('Permissions required!');
    }

Essentially, we are making an API call to /<user_id>/feed, using the POST method (second argument) and an array as a third argument for the data to be sent. In this case, this third argument supports message, link, picture, caption, name and description. Here’s the code:

$facebook->api('/'.$uid.'/feed', 'post', array(
    'message' => 'The message',
    'name' => 'The name',
    'description' => 'The description',
    'caption' => 'The caption',
    'picture' => 'http://i.imgur.com/yx3q2.png',
    'link' => 'http://net.tutsplus.com/'
));

Here’s how it is posted.

Some Additional Information you Should Know:

The user can easily revoke permissions with two clicks in his or her wall. You should heavily test what might happen if a user revoked one or more permissions that are vital for the proper functioning of your website, or even if the application is fully removed. This is important.


5. Conclusion

While Facebook’s authentication capabilities are indeed useful, since so many people are on Facebook these days, using it as the only method of authentication in a site is not recommended. What about those who don’t have Facebook accounts? Are they not allowed to access your application? Thanks for reading!

Rafael Soto is faelsoto on Codecanyon
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Gaurav Sharma

    Nice Post. Could you also please do one for Python / Django?

    • w1sh

      What an intelligent young fellow you are, Gaurav. :)

  • http://nike1.se/ Nike

    Really helpful! Thanks.

  • http://ww.fcicafe.com Mohamed Fouad

    nice tutorial but i was wondering if you could explain how to send notification to users?

  • EllisGL

    Thoughts: You could have a column named “facebook” and store the “uid” in it.

  • http://montanaflynn.me Montana Flynn

    Cool, this is a great tut. What ever happened to OpenID?!

    • http://www.hambrook.co.nz Rick Hambrook

      Facebook saw the open standard that is OpenID, then spat in it’s face and did their own thing.

    • Markusk

      It joined Microsoft’s Passport in nirvana. Well not completely. If I remeber correctly MySpace uses OpenID. I’m really surprised that people – for what ever reason – feel that a federated identity that is hosted by Facebook (who earn money buy selling profiles) is so much better than one hosted by Microsoft.

  • http://www.onyxsolution.com OnYx

    this is interesting! dont know if I ever will use it but you never know…
    Thank you!

  • http://www.deluxeblogtips.com Rilwis

    Great tutorial. Nowadays, Facebook connection is used in almost website. I’d want to look for this tutorial for a long time. Thanks for sharing.

  • Matas

    Great stuff mate ;) Very useful!

  • vaff

    I think the Graph Api is simple enough … if you want user info you just do “/me” and if you want the big picture you just do “/me/picture?type=large” you don’t need the uid, since “/me” is always the logged in user

    • http://therr.org Rafael Soto
      Author

      Yeah, while I agree it’s quite easy, the official documentation is not as complete as it should be. Also, I think if you need the picture large, the thumbnail and the user first and last name, it is better to call the legacy API or you will be requesting 4 Graph API calls.

  • Jordan

    Awesome tutorial. Does anyone know if it is possible to allow a user to take a photo from my site (we have a site of photos of our students) and allow them to directly make it their profile picture?

    • http://therr.org Rafael Soto
      Author

      It is not possible. You can though, upload a picture on behalf of your users and then tell them to click “make my profile picture”.

  • http://shutterskills.com Rish

    Very nice tutorial. Although, the one who doesn’t know SQL may wonder what the hell is happening :P

  • http://butenas.com Ignas

    This is really nice one :) Will use something from it :)

  • David

    This is phenomenal. My friends and I were wondering how to do exactly this and we were continually told that the Facebook API is scary. Thanks!

  • paulon

    nice blog.. i second emotion to Mohamed Fouad, can u explain how to send notification?

  • ED

    Very nice
    but just a note about php comments.
    they are prefixed with “//” not like c++ “#”

  • paulon

    one more thing, i follow along with your samples i get download your sample fb-connect files and i got an error

    Fatal error: Uncaught exception ‘Exception’ with message ‘Facebook needs the CURL PHP extension.’ in D:\xampp\htdocs\fb_connect\facebook.php:4 Stack trace: #0 D:\xampp\htdocs\fb_connect\login_facebook.php(11): require() #1 {main} thrown in D:\xampp\htdocs\fb_connect\facebook.php on line 4

    why?

    • Justin

      do you have xampp setup to allow curl? your testing environment is more than likely missing some needed settings. try on a live sever to see if it works.

      • paulon

        yes i have xampp up and running,. but i do not know where to set the curl to be allowed.. ?

      • paulon

        the sample is working now, i activated the [php_curl.dll] from php.ini and it works fine now… tnx..

    • Tyler

      The answer is right there in your error!
      You must not have CURL enabled in your build of PHP.

      Based on the filepath in your error, looks like you’re running locally on windows.

      Try this:
      http://www.tildemark.com/programming/php/enable-curl-with-xampp-on-windows-xp.html

  • paulon

    im having problem with the login_facebook.php

    The page isn’t redirecting properly

    Firefox has detected that the server is redirecting the request for this address in a way that will never complete.

    • http://therr.org Rafael Soto
      Author

      It happens because it’s the basic example for authentication. The script gets the URL to be redirected to Facebook and since the app has been approved by the user, it redirects to the same script. Hence the loop.

      I should’ve specified it though, my bad. Sorry about that.

      • paulon

        so what is the alternative?

    • http://www.smartsocket.net Jerome

      I’m having the same issue. For some reason, Facebook isn’t properly creating a session so there is an infinite redirect loop.

      Any help on this issue?

      • http://www.smartsocket.net Jerome Doby

        Nevermind. I went back through and checked my settings.

        Ensure that your APP ID and SECRET KEY are correct!

  • http://www.twentyeleven.co.uk Nigel

    Something a bit more in laymans terms would be really helpful for those with no experience in this.

  • paulon

    well i have a little experience using fb-connect but not using FQL, got work it out using Javascript SDK though FQL is a bit advance but its pretty much the same.

  • paulon

    sori got mis type, string “FQL” suppose to be PHP SDK..

    :D

  • http://variable3.com/blog/ Harsha M V

    i want some help to implement this on cakephp framework.

  • http://twitter.com/xrommelx xRommelx

    this is really useful

  • http://www.ate5.com Jordan Walker

    Great write on a feature to integrate with Facebook via oAuth.

  • http://www.niurexx.com izainurie

    thanks…you’ve saved my day….

  • EllisGL

    You might need to add “CURLOPT_SSL_VERIFYPEER => 0,” to the facebook.php in the “$CURL_OPTS”

  • http://tutorialstipstricks.com Tutorials Tips Tricks

    this is really useful

  • http://www.amazone.com DONOBERA

    Very Helpful, thanks….
    requests tutorial for connect twitter, update status twitter, and change ‘update via’ my app on twitter.

  • http://www.hastishah.com Hastimal Shah

    Great tutorial.. I was searching for this as i need to implement this in my current project..
    It was posted on right time for me i can say..
    Thanks a lot

  • paulon

    well im still having problem with this. it turns out that api doesn’t forwarding me at the right page at all
    everything works fine as i follow your blog until the login_facebook.php ain’t forward me at the right page at all.

    here is the error:
    =================
    The page isn’t redirecting properly

    Firefox has detected that the server is redirecting the request for this address in a way that will never complete.
    =================

    • Amos Vryhof

      I’ve gotten similar issues to what you are having, but it was caused by mod_security when facebook redirected back to my page. I can’t remember what rule it was hitting, but once I disabled it, the issue went away.

  • http://www.codeforest.net Codeforest

    Very interesting tutorial. I was looking to find a tutorial on Facebook connect, but this one is far the best.

    Thanks

  • http://www.nouveller.com/ Benjamin Reid

    Nice to see a tutorial on this, Facebook login seems to be used more than Oauth! I might give this a go on a little web app’ I’m currently knocking together. I’ll be keeping the regular registration though. It might be interesting to see the percentage of people that opt for Facebook…

  • http://amrelgarhy.com Amr ElGarhy

    Great post, can you make another post the same as this but using .Net? it will be great if you did.
    Thanks,

  • http://www.greek-paris.com Cecile

    Hi and thanks so much for this tutorial ! I’m following it very carefully and up to step 3, it works fine ! I just have one questions: has all the code after step 3 to be included in facebook_login.php ? If not, where should I write it ?

    Thanks !

  • http://www.kevinpapst.de Kevin

    You should not set $opts[CURLOPT_SSL_VERIFYPEER] = false; in the facebook.php file directly, but inject it before you call the constructor. The Facebook guys made the $CURL_OPTS array static for that purpose:

    Facebook::$CURL_OPTS[CURLOPT_SSL_VERIFYPEER] = false;
    $facebook = new Facebook(…);

    Also, note that you could simply download the cacert.pem from http://curl.haxx.se/docs/caextract.html and set it via:
    Facebook::$CURL_OPTS[CURLOPT_CAINFO] = ‘/path/to/cacert.pem’

    Now you don’t need to set CURLOPT_SSL_VERIFYPEER because certificate will validate properly.

    • EllisGL

      @Kevin: Yeah that would be the better way. Now if we had all the other SSO’s implemented so easily.

  • Julius

    Very nice tutorial. It will be very helpful in my future web developments..

    Continue posting good tutorials..

  • http://www.greek-paris.com Cecile

    Ok now I am a little lost. I finally downloaded the source files but I don’t understand where should I put all the different files like home_auth.php etc.. ? In my localhost root folder ? And for some reason which I can’t get, the original login-facebook doesn’t work anymore although I am still using the same as at the beginning..! Sorry but I will need a hand on this … Thanks in advance !

  • http://www.tastybytes.net Brian

    Would have been great about 6 months ago… still is though, Thanks!!!

  • Philipp Schuch

    Hey, nice Tut. I was working on facebook Connect APIs this week. This Tut is good Stuff for the Weekend to work on my Code.

  • http://krike.cmstutorials.org krike

    awesome :D I just needed that for one of my projects at school. Thank you so much

  • http://krike.cmstutorials.org krike

    I can’t create the app, it just gives me a blank page when I create the app on facebook. Is the service down? anyone else having this problem?

    • http://krike.cmstutorials.org krike

      nvm, it gave me a blank page but still created the app. I ended up with 5 applications :D

  • http://www.technewsblog.co.uk Steve

    Awesome tutorial. Thanks a lot :)

  • Thomas

    I’m trying this tutorial out but I get the following error

    “There was an error.”

    What could be the cause of that?

  • Thomas

    hello,

    I posted a comment before. But it seemed to have disappeard.

    I’m trying to get this to work but I have a problem.

    Most of the time when i go to login_facebook.php i get this error: “There was an error.”

    But sometimes i do get trough.

    What could be the problem?

  • Onny

    Thanks a lot! That’s amazing source for beign of this. Nice work, Nettuts!

  • http://tvprofil.net kowach

    Hi,

    I have implemented oauth http://tvprofil.net/oauth.php , but when I require for users email, Facebook offers as default proxymail xxxxxxxxxxxxxxxxxxxxxxx@proxymail.facebook.com, but I need users real email. How can I require real email?

    http://tvprofil.net/img/change_fb_mail.jpg

    The average user will click allow by default and $user = $facebook->api(‘/me’); will always return proxymail :(, until user removes my application and reauths again, but that’s too complicated for average user.

  • Deren

    Thanks, it’s a great tut :D
    would you know how to add the logo/icon into the app?

  • bugz

    GRRRRRRRRRRRT script

    One issue : the login url page with extended permissions open the facebook page in the iframe

    Need help, i am new to the facebook application. Am i missing any configuration?

    Thanks

  • http://www.businessinsider.com Jason

    Only problem is their phasing out Facebook Connect. http://mashable.com/2010/04/21/facebook-kills-facebook-connect/

  • http://www.tenaxtechnologies.com complex web development

    Really helpful! Thanks.

  • Anton

    Do we need checking the extended permissions?
    It’s seems that user can not revoke permissions, except publish_stream.