My Web Log Book

Ruby version of Facebook’s get_facebook_cookie in PHP

Facebook provides an example of Single Sign-on that includes a method of verifying the authenticity of facebook’s cookie that is set by their JavaScript SDK. The method is defined as:

<?php
  define('FACEBOOK_APP_ID', 'your application id');
  define('FACEBOOK_SECRET', 'your application secret');
  
  function get_facebook_cookie($app_id, $application_secret)
  {
      $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;
  }
  
  $cookie = get_facebook_cookie(FACEBOOK_APP_ID, FACEBOOK_SECRET);
?>

Here’s one for Ruby.

require 'cgi'
require 'digest/md5'

def get_facebook_params(app_id, app_secret, cookie)
  # unquote cookie value
  cookie.gsub!(/^"|"$/, '')
  
  # construct key, value pairs
  params = CGI.parse(cookie)
  
  # params contains keys and values of the form
  # {"session_key" => ["..abcdef.."], "uid" => ["123456789"]}
  # we need to unwrap each value out of the array into something like this
  # {"session_key" => "..abcdef..", "uid" => "123456789"}
  params = Hash[*params.sort.flatten]

  # take sig out
  sig = params.delete("sig")
  
  payload = ''
  params.sort.each do |pair|
    key, value = pair
    payload = payload + "#{key}=#{value}"
  end
  
  return nil if sig != Digest::MD5.hexdigest(payload + app_secret)
  
  return params
end