Oauth 2.0 - facebook changes and cookie problem in Codeigniter

Lately Facebook forced all developers to use oauth 2.0 by setting by default oauth:true in FB.init();

The most important changes are:

  • Cookie name is now 'fbsr_'. not 'fbs_'
  • Cookie has more changes than you think ;o)
  • perms are now scope - so now instead of writing in e.g. login button perms="email,publish_stream" you write scope="email,publish_stream"
  • to get access_token we need to have `magic code` first
  • if you're using some client-side scripting too, then instead of FB.getSession use FB.getAuthResponse - (thanks ajquick)

...

Things you need to change are probably similar for other frameworks if you don't use SDK. I tested this solution for CodeIgniter 2.x. But it should work for earlier ver too.

This is quick and dirty, and it was tested for authentication. If you have problem only with cookie function skip first two steps and check if new function works for you.

If you are making some rewriting now I encourage you to rewrite code so you can use their SDK. Maybe next time, after so many changes the only thing you will have to do is update SDK.

First of all we need to add to our FB.init() oauth:true. Although it's now default, but you never know if they change it back. Just for fun.

Next, change in your login link/button word perms to scope. Otherwise you will get : "OAuth2 specification states that 'perms' should now be called 'scope'. Please update." error. It's just changing name, nothing else.

Then if your class use cookie you need to change it name from 'fbs_' to 'fbsr_'. But there was more changes. If you use function get_facebook_cookie() like one below (as I saw in the web many people are):

function get_facebook_cookie() 
{
    // get the fb app id, and secret from CI config source
    $CI =& get_instance();
    $app_id = $CI->config->item('facebook_app_id');
    $application_secret = $CI->config->item('facebook_app_secret');
    if(isset($_COOKIE['fbs_' . $app_id])){
        $args = array();
         parse_str(trim($_COOKIE['fbs_' . $app_id], '\\"'), $args);
         ksort($args);
        $payload = '';
        foreach ($args as $key => $value) {
             if ($key != 'sig') {
                $payload .= $key . '=' . $value;
            }
         }
         if (md5($payload . $application_secret) != $args['sig']) {
             return null;
        }
         return $args;
    }
    else{
        return null;
    }
 }

change it to something like that:

 function get_facebook_cookie() {
     $CI =& get_instance();
     $app_id = $CI->config->item('facebook_app_id');
     $application_secret = $CI->config->item('facebook_app_secret');
      if(isset($_COOKIE['fbsr_' . $app_id])){
         list($encoded_sig, $payload) = explode('.', $_COOKIE['fbsr_' . $app_id], 2);
   
         $sig = base64_decode(strtr($encoded_sig, '-_', '+/'));
         $data = json_decode(base64_decode(strtr($payload, '-_', '+/')), true);
  
         if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
             return null;
         }
         $expected_sig = hash_hmac('sha256', $payload,
         $application_secret, $raw = true);
          if ($sig !== $expected_sig) {
              return null;
          }
          $token_url = "https://graph.facebook.com/oauth/access_token?"
         . "client_id=" . $app_id . "&client_secret=" . $application_secret. "&redirect_uri=" . "&code=" . $data['code'];
   
          $response = @file_get_contents($token_url);
          $params = null;
          parse_str($response, $params);
          $data['access_token'] = $params['access_token']; 
          return $data;
      }else{
          return null;
     }
}

If you use in other places that function, probably you also use it for getting session_key, maybe for logout url. Anyway, it seems that session_key is now `magic` code, so add to function

$data['session_key'] = $data['code'];

just before return if you use that in many places and you are so lazy that you don't want rewrite it there.

The changed cookie function works also for getting list of friends. I'm guessing that will work for all functions that use something like that:

@json_decode(file_get_contents( 'https://graph.facebook.com/me?access_token=' .
$cookie['access_token']), true);

However I recommend to use PHP SDK from facebook, because if they change something again, most likely you will have to update only SDK, and not rewriting your code over and over again.

  • Share it on Twitter
  • Share it on Facebook
  • Share it on Google+
Tweet this

Comments (2)Add comment

mgabor

This helped me soo much, I don't know words to express how grateful I am for this!

ajquick

Thanks for this. I had been searching for days and days to figure out why my script didn't work. All the other sites out there were only mentioning the perms to scope change and the Oauth: true change. The cookie thing was what I needed to know! Also one thing you didn't have was the change from "response" to "authresponse" or something of the sort...

Take part in the discussion





8 + 7
(* will not be published)