Archive for the ‘Facebook’ Category.

Set age restrictions on Facebook apps with the Graph API

This one drove me nuts. Facebook allows developers to restrict applications based on a user’s age and location. This was a pretty important requirement for a recent alcohol brand application we were developing. The api method is called admin.setRestrictionInfo. It makes what would otherwise be a tedious process very simple. No ‘enter your birthdate’ screens, no worrying about posts created by the application soliciting underage users. The method even takes a special parameter called ‘type’ that can be set to ‘alcohol’ (currently the only option for this parameter) which blocks users based on their local drinking age.

Sounds perfect. Until you try implementing it.

The abysmal Facebook documentation provides no examples of how to make this call. In scouring the forums, I discovered that the method only needs to be called once, and this particular application made no use of server-side SDKs, so there wasn’t a convenient way to make the call. I started making calls to the API via simple browser get requests, knowing that the response would be ‘true’ if the call was successful (that, believe it or not, was actually specified in the documentation). I kept getting a variety of error responses. The structure of the request is:

1
https://api.facebook.com/method/admin.setRestrictionInfo?access_token=[YOUR_ACCESS_TOKEN]&format=json&restriction_str={%22type%22:%22alcohol%22}

I was getting the access_token from the “Access Token” string found on the application page in the developer dashboard. But for whatever reason, this method requires you to pass your application id pipe-delimited with your application secret. This is the url structure that ultimately returned ‘true’ when entered into the browser.

1
https://api.facebook.com/method/admin.setRestrictionInfo?access_token=[APP_ID]|[APP_SECRET]&format=json&restriction_str={%22type%22:%22alcohol%22}

A very useful method with absolutely useless documentation. Hope this helps save someone else as much time as I wasted figuring this out…

Configuring GoDaddy SSL Certificates on Nginx

There are a number of articles out there on how to install security certificates from GoDaddy on an Nginx server, but the GoDaddy process seems to have changed since those articles were published, so I thought I would jot down the process I had to follow in the hopes that someone else finds it useful.

First, it’s worth mentioning that GoDaddy has pretty cheap SSL certificates. They aren’t the greatest, they just verify the domain, but they are pretty useful for Facebook apps, which is especially important given Facebook’s recent drive to have more users access Facebook via https. This article was immensely helpful in getting me started in the right direction, but it left out 2 important steps that kept the certificate from being properly recognized.

You’ll need to break from the instructions in that article after step 2.3. When you select ‘other’ from the webserver dropdown on GoDaddy, your zip will not include the intermediary cert (whether it’s a Starfield or GoDaddy cert). You’ll need this intermediary cert, so head on over to GoDaddy’s cert repo and download either the gd_intermediate.crt (or sf_intermediate.crt if it’s a Starfield cert) and upload to your server.

Instead of running

1
cat www.mysite.com.crt gd_bundle.crt > mysite_combined.crt

Run the following (replacing your domain name and intermediate cert name as necessary):

1
cat www.mysite.com.crt gd_intermediate.crt gd_bundle.crt > mysite_combined.crt

From there, the previously cited article should get you the rest of the way… BUT, there’s one more issue. When you try restarting Nginx, you’ll likely see an error. The intermediary cert is missing a line break, so you’ll need to open up the combined cert and change this:

1
-----END CERTIFICATE----------BEGIN CERTIFICATE-----

To this:

1
2
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----

Integrating Facebook Connect with CakePHP’s Auth Component

This post is out of date; place check out any of the numerous Cakephp 2+ versions of Facebook Websites implementations out there.

I wanted to be able to leverage all of the advantages of using Cake’s built in Auth component in my latest application; problem was that the application needed to allow for both normal user accounts and Facebook Connect generated user accounts. I struggled for a while to find the most seamless approach, and then it clicked — dynamically set Auth->fields.

First, drop the facebook client libraries in a app/vendors/facebook folder. Then, in your app_controller, import the classes, and set some properties:

1
2
3
4
5
6
7
8
9
10
<?php
App::import('Vendor', 'facebook/facebook');

class AppController extends Controller {
    var $components = array('Auth');
    var $uses = array('User');
    var $facebook;
    var $__fbApiKey = 'your_key';
    var $__fbSecret = 'your_secret';
}

Next we’ll overwrite the inherited __construct method to instantiate a Facebook Object:

1
2
3
4
5
6
7
8
9
  function __construct() {
    parent::__construct();
       
    // Prevent the 'Undefined index: facebook_config' notice from being thrown.
    $GLOBALS['facebook_config']['debug'] = NULL;
       
    // Create a Facebook client API object.
    $this->facebook = new Facebook($this->__fbApiKey, $this->__fbSecret);
  }

In our beforeFilter method, we define the default Auth properties, call a private __checkFBStatus method, and pass any user data to the view:

1
2
3
4
5
6
7
8
9
10
11
function beforeFilter() {
    // Authentication settings
    $this->Auth->fields = array('username' => 'email', 'password' => 'password');
    $this->Auth->logoutRedirect = '/';

    //check to see if user is signed in with facebook
    $this->__checkFBStatus();

    //send all user info to the view
    $this->set('user', $this->Auth->user());
}

Next we’ll define the private method __checkFBStatus that’s called in our beforeFilter method. First we check to make sure $this->Auth->User isn’t already set by a normal user account, and we check to see if there’s a logged in facebook user. The logged in facebook user is available after we use the JavaScript API to log facebook users into the site.

1
2
3
    private function __checkFBStatus(){
        //check to see if a user is not logged in, but a facebook user_id is set
        if(!$this->Auth->User() &amp;&amp; $this->facebook->get_loggedin_user()):

Next, see if this user has already logged in, and therefore already has an entry in our User table:

1
2
3
4
5
6
7
            //see if this facebook id is in the User database; if not, create the user using their fbid hashed as their password
            $user_record =
                $this->User->find('first', array(
                    'conditions' => array('fbid' => $this->facebook->get_loggedin_user()),
                    'fields' => array('User.fbid', 'User.fbpassword', 'User.password'),
                    'contain' => array()
                ));

If no record was found, we create a new record for this user. We are setting 3 variables, fbid, fbpassword, and password. The fbpassword field will hold a randomly generated 20 character string un-hashed so that we can access the value of the field directly from the database. We retrieve this value based on the fbid field, hash it, and that’s our password as the Auth Component expects:

1
2
3
4
5
6
7
8
9
            //create new user
            if(empty($user_record)):
                $user_record['fbid'] = $this->facebook->get_loggedin_user();
                $user_record['fbpassword'] = $this->__randomString();
                $user_record['password'] = $this->Auth->password($user_record['fbpassword']);
               
                $this->User->create();
                $this->User->save($user_record);
            endif;

We need to then update our Auth Component’s fields property to use fbid as the username.

1
2
3
4
5
6
7
8
            //change the Auth fields
            $this->Auth->fields = array('username' => 'fbid', 'password' => 'password');

            //log in the user with facebook credentials
            $this->Auth->login($user_record);
           
        endif;
    }

Here’s the complete app_controller.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<?php
App::import('Vendor', 'facebook/facebook');

class AppController extends Controller {
    var $components = array('Auth');
    var $uses = array('User');
  var $facebook;
  var $__fbApiKey = 'your_key';
  var $__fbSecret = 'your_secret';
   
  function __construct() {
    parent::__construct();
       
    // Prevent the 'Undefined index: facebook_config' notice from being thrown.
    $GLOBALS['facebook_config']['debug'] = NULL;
       
    // Create a Facebook client API object.
    $this->facebook = new Facebook($this->__fbApiKey, $this->__fbSecret);
  }

    function beforeFilter() {
    // Authentication settings
    $this->Auth->fields = array('username' => 'email', 'password' => 'password');
    $this->Auth->logoutRedirect = '/';

        //check to see if user is signed in with facebook
        $this->__checkFBStatus();

        //send all user info to the view
        $this->set('user', $this->Auth->user());
  }

    private function __checkFBStatus(){
        //check to see if a user is not logged in, but a facebook user_id is set
        if(!$this->Auth->User() &amp;&amp; $this->facebook->get_loggedin_user()):

            //see if this facebook id is in the User database; if not, create the user using their fbid hashed as their password
            $user_record =
                $this->User->find('first', array(
                    'conditions' => array('fbid' => $this->facebook->get_loggedin_user()),
                    'fields' => array('User.fbid', 'User.fbpassword', 'User.password'),
                    'contain' => array()
                ));

            //create new user
            if(empty($user_record)):
                $user_record['fbid'] = $this->facebook->get_loggedin_user();
                $user_record['fbpassword'] = $this->__randomString();
                $user_record['password'] = $this->Auth->password($user_record['fbpassword']);
               
                $this->User->create();
                $this->User->save($user_record);
            endif;

            //change the Auth fields
            $this->Auth->fields = array('username' => 'fbid', 'password' => 'password');

            //log in the user with facebook credentials
            $this->Auth->login($user_record);
           
        endif;
    }

    private function __randomString($minlength = 20, $maxlength = 20, $useupper = true, $usespecial = false, $usenumbers = true){
        $charset = "abcdefghijklmnopqrstuvwxyz";
        if ($useupper) $charset .= "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        if ($usenumbers) $charset .= "0123456789";
        if ($usespecial) $charset .= "~@#$%^*()_+-={}|][";
        if ($minlength > $maxlength) $length = mt_rand ($maxlength, $minlength);
        else $length = mt_rand ($minlength, $maxlength);
        $key = '';
        for ($i=0; $i<$length; $i++){
            $key .= $charset[(mt_rand(0,(strlen($charset)-1)))];
        }
        return $key;
    }

}
?>

Next we need to make a few changes to our default.ctp layout; first add the facebook namespace:

1
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:fb="http://www.facebook.com/2008/fbml">

Add these 2 javascript snippets (be sure your xd_receiver.htm file is accessible in your webroot):

1
2
<script type="text/javascript" src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"></script>
<script type="text/javascript">FB.init("your_api_key","/xd_receiver.htm");</script>

Last step, place your login and logout buttons in your default view. Few things to point out here; onlogin=”window.location.reload();” will cause the page to reload after a successful Facebook Connect login. This is how we are able to access $this->facebook->get_loggedin_user() in our app_controller to force the manual Auth login. If the user is a facebook user (determined with $user['User']['fbid'] > 0), add an onclick event that calls the FB.Connect.logout() function with a redirect URL as the parameter. This will log the User out of the Auth Component after it logs the user out of Facebook.

1
2
3
4
5
6
7
8
9
10
11
<?php
            if(!empty($user)):
                if($user['User']['fbid'] > 0):
                    echo $html->link('logout', '#', array('onclick' => 'FB.Connect.logout(function() { document.location = \'http://your_server/users/logout/\'; }); return false;'));
                else:
                    echo $html->link('logout', array('controller' => 'users', 'action' => 'logout'));
                endif;
            else:
                echo '<fb:login-button onlogin="window.location.reload();"></fb:login-button>';
            endif;
?>

One last thing to consider, for security reasons… In your login method, be sure only users with fbid = 0 can login via the normal auth fields (username / password). Just an extra precaution considering you have an unhashed password in your database for those facebook users.

Hope that helps someone else out. Let me know if you run into any problems, I slapped this post up quickly and hopefully didn’t make many mistakes. And per Matt’s spot-on recommendation (via pseudocoder.com), I’m working on rolling this into a plugin… Will post when it’s complete.