Index: fb_devel.js
===================================================================
--- fb_devel.js	(revision 3789)
+++ fb_devel.js	(working copy)
@@ -15,11 +15,20 @@
     // before fb.js has a chance to initilize it!  To fix: use browser
     // to view page source, find all <script> tags that include all.js
     // and get rid of them.
+    // NOTE: this seems to get triggered sometimes, even when set up correctly.  Race condition?
     debugger; // not verbose.
-    if (Drupal.settings.fb.verbose) {
-      alert("fb_devel.js: Facebook JS SDK initialized badly."); // verbose
+    if (Drupal.settings.fb_devel.verbose) {
+      alert("fb_devel.js: Facebook JS SDK initialized witout app id!"); // verbose
     }
   }
+
+  var root = jQuery('#fb-root');
+  if (root.length != 1) {
+    debugger; // not verbose.
+    if (Drupal.settings.fb_devel.verbose) {
+      alert("fb_devel.js: no <div id=fb-root> found!"); // verbose
+    }
+  }
 };
 
 /**
Index: fb_devel.module
===================================================================
--- fb_devel.module	(revision 3789)
+++ fb_devel.module	(working copy)
@@ -48,7 +48,7 @@
   if (user_access('access devel information')) {
     // Add our module's javascript.
     drupal_add_js(drupal_get_path('module', 'fb_devel') . '/fb_devel.js');
-    fb_js_settings('verbose', fb_verbose());
+    drupal_add_js(array('fb_devel' => array('verbose' => fb_verbose())), 'setting');
   }
 
   // fb_settings.inc sanity check.
@@ -306,7 +306,24 @@
   }
 }
 
+
 /**
+ * Implements hook_footer().
+ */
+function fb_devel_footerXXX($is_front) {
+  $output = "<!-- fb_devel_footer() -->\n";
+  $output .= "<script type=\"text/javascript\">\n";
+  $output .= "<!--//--><![CDATA[//><!--\n";
+  $output .= "  jQuery(document).bind('fb_init', FB_Devel.initHandler);\n";
+  //$output .= "  FB_Devel.sanityCheck()\n";
+  $output .= "\n//--><!]]>\n";
+  $output .= "\n</script>\n";
+  return $output;
+}
+
+
+
+/**
  * Provides a page with useful debug info.
  *
  * @TODO - clean this up and rely less on drupal_set_message() and dpm().
@@ -316,19 +333,22 @@
   global $user;
 
   if (isset($_REQUEST['require_login']) && $_REQUEST['require_login'])
-    $_fb->require_login();  // @TODO - find a way to do this with new api.
+    $_fb->require_login();
 
   if ($_fb) {
     // TODO: determine whether connect page or canvas.
 
     drupal_set_message(t("session name: " . session_name()));
+    drupal_set_message(t("session id: " . session_id()));
     drupal_set_message(t("cookie domain: " . fb_settings(FB_SETTINGS_COOKIE_DOMAIN)));
-    drupal_set_message(t("session id: " . session_id()));
+
     if (isset($_COOKIE['fbs_' . $_fb_app->apikey]))
       drupal_set_message(t("fbs_" . $_fb_app->apikey . ": " . $_COOKIE["fbs_" . $_fb_app->apikey]));
     drupal_set_message(t("<a href=\"!url\">processed link</a>, <a href=!url>unprocessed</a>", array('!url' => url('fb/devel'))));
     drupal_set_message(t("getUser() returns " . $_fb->getUser()));
 
+    drupal_set_message(t("getAccessToken() returns " . $_fb->getAccessToken()));
+
     drupal_set_message(t("base_url: " . $GLOBALS['base_url']));
     drupal_set_message(t("base_path: " . $GLOBALS['base_path']));
     drupal_set_message(t("url() returns: " . url()));
@@ -351,7 +371,6 @@
   dpm($_COOKIE, 'cookie');
   dpm($_REQUEST, "Request");
   //dpm($_fb_app, "fb_app");
-  drupal_set_message(t("session_id returns " . session_id()));
   dpm($_SESSION, "session:");
 
   return "This is the facebook debug page.";
@@ -426,8 +445,15 @@
 function fb_devel_fbu_page($fbu = NULL) {
   global $_fb, $_fb_app;
   if ($fbu) {
+    // Uses FQL
+    $info = fb_users_getInfo(array($fbu), $_fb);
+    $output = "<p>Debug FQL info about facebook id $fbu ({$info[0]['name']}):</p>\n";
+    $output .= "<img src=http://graph.facebook.com/$fbu/picture></img>";
+    $output .= "<pre>" . print_r($info[0], 1) . "</pre>";
+
+    // Use new graph api
     $info = $_fb->api($fbu, array('metadata' => 1));
-    $output = "<p>Debug info about facebook id $fbu ({$info[name]}):</p>\n";
+    $output .= "<p>Debug info about facebook id $fbu ({$info['name']}):</p>\n";
     $output .= "<img src=http://graph.facebook.com/$fbu/picture></img>";
     $output .= "<pre>" . print_r($info, 1) . "</pre>";
 
@@ -448,7 +474,7 @@
       //dpm($friends, "$fbu/friends returned");
       $items = array();
       foreach ($friends['data'] as $data) {
-        $items[] = l($data['name'], "fb/devel/fbu/{$data[id]}");
+        $items[] = l($data['name'], "fb/devel/fbu/{$data['id']}");
       }
       if (count($items)) {
         $output .= "\n<p>Known friends:<ul><li>";
@@ -579,8 +605,7 @@
   $info['arg(1) is'] = arg(1);
   $info['session_id'] = session_id();
   $info['session_name'] = session_name();
-  $info['fbsettings(FB_SETTINGS_COOKIE_DOMAIN)'] = fb_settings(FB_SETTINGS_COOKIE_DOMAIN);
-
+  $info['fb_settings()'] = fb_settings();
   $info['request'] = $_REQUEST;
   $info['user'] = $GLOBALS['user'];
   $info['fb_app'] = $_fb_app;
@@ -604,7 +629,7 @@
     catch (FacebookApiException $e) {
       fb_log_exception($e, "failed to get app properties");
     }
-    $info["fb->getSession()"] = $_fb->getSession();
+   // $info["fb->getSession()"] = $_fb->getSession();
     $info["fb->getSignedRequest()"] = $_fb->getSignedRequest();
     if ($fbu) {
       try {
@@ -613,7 +638,11 @@
                                            ));
       }
       catch (FacebookApiException $e) {
-        fb_log_exception($e, "failed to look up _fb->api($fbu)");
+        if (fb_verbose() == 'extreme') {
+          // After oauth upgrade, this exception is thrown always, when using app token.
+          // So only show error when fb_verbose is extreme.  Hopefully facebook will fix the issue.
+          fb_log_exception($e, "failed to look up _fb->api($fbu)."); // Dont show token, it can inlude app secret.  using token " . fb_get_token($_fb));
+        }
       }
     }
   }
Index: fb.theme.inc
===================================================================
--- fb.theme.inc	(revision 3789)
+++ fb.theme.inc	(working copy)
@@ -16,12 +16,12 @@
   $options += array(
     'attributes' => array(),
   );
-  if (!isset($options['attributes']['perms'])) {
+  if (!isset($options['attributes']['scope'])) {
     // Which permissions to prompt for?
     $perms = array();
     drupal_alter('fb_required_perms', $perms);
     if (count($perms)) {
-      $options['attributes']['perms'] = implode(',', $perms);
+      $options['attributes']['scope'] = implode(',', $perms);
     }
   }
 
Index: fb.js
===================================================================
--- fb.js	(revision 3789)
+++ fb.js	(working copy)
@@ -27,10 +27,14 @@
  * Finish initializing, whether there is an application or not.
  */
 FB_JS.initFinal = function(response) {
-  var status = {'session' : response.session, 'response': response};
+  var status = {
+    'session' : response.authResponse, // deprecated
+    'auth': response.authResponse,
+    'response': response
+  };
   jQuery.event.trigger('fb_init', status);  // Trigger event for third-party modules.
 
-  FB_JS.sessionChange(response); // This will act only if fbu changed.
+  FB_JS.authResponseChange(response); // This will act only if fbu changed.
 
   FB_JS.eventSubscribe();
 
@@ -42,7 +46,7 @@
  */
 FB_JS.eventSubscribe = function() {
   // Use FB.Event to detect Connect login/logout.
-  FB.Event.subscribe('auth.sessionChange', FB_JS.sessionChange);
+  FB.Event.subscribe('auth.authResponseChange', FB_JS.authResponseChange);
 
   // Q: what the heck is "edge.create"? A: the like button was clicked.
   FB.Event.subscribe('edge.create', FB_JS.edgeCreate);
@@ -75,10 +79,11 @@
  */
 FB_JS.reload = function(destination) {
   // Determine url hash.
-  var session = FB.getSession();
+  var auth = FB.getAuthResponse();
+
   var fbhash;
-  if (session != null)
-    fbhash = session.sig; // Use sig rather than compute a new hash.
+  if (auth != null)
+    fbhash = auth.signedRequest; // Use sig rather than compute a new hash.
   else
     fbhash = 0;
 
@@ -132,15 +137,22 @@
 };
 
 // Facebook pseudo-event handlers.
-FB_JS.sessionChange = function(response) {
+FB_JS.authResponseChange = function(response) {
+  //debugger;
   if (response.status == 'unknown') {
     // @TODO can we test if third-party cookies are disabled?
   }
 
-  var status = {'changed': false, 'fbu': null, 'session': response.session, 'response' : response};
+  var status = {
+    'changed': false,
+    'fbu': null,
+    'session': response.authResponse, // deprecated,  still needed???
+    'auth': response.authResponse, // still needed???
+    'response' : response
+  };
 
-  if (response.session) {
-    status.fbu = response.session.uid;
+  if (response.authResponse) {
+    status.fbu = response.authResponse.userID;
     if (Drupal.settings.fb.fbu != status.fbu) {
       // A user has logged in.
       status.changed = true;
@@ -152,6 +164,7 @@
 
     // Sometimes Facebook's invalid cookies are left around.  Let's try to clean up their crap.
     // Can get left behind when third-party cookies disabled.
+    // @TODO: Still needed with new oauth??? Have cookies been renamed (fbsr_...)???
     FB_JS.deleteCookie('fbs_' + FB._apiKey, '/', '');
     FB_JS.deleteCookie('fbs_' + Drupal.settings.fb.apikey, '/', '');
   }
@@ -180,7 +193,7 @@
   };
 
   if (status.session) {
-    data.fbu = status.session.uid;
+    data.fbu = status.session.userID;
     // Suppress facebook-controlled session.
     data.fb_session_handoff = true;
   }
@@ -196,7 +209,7 @@
   if (Drupal.settings.fb.ajax_event_url) {
 
     // Session data helpful in ajax callbacks.  See fb_settings.inc.
-    request_data.fb_js_session = JSON.stringify(FB.getSession());
+    // request_data.fb_js_session = JSON.stringify(FB.getSession()); // FB.getSession() FAILS! REMOVE or REPLACE.
     if (typeof(Drupal.settings.fb_page_type) != 'undefined') {
       request_data.fb_js_page_type = Drupal.settings.fb_page_type;
     }
Index: fb_connect.js
===================================================================
--- fb_connect.js	(revision 3789)
+++ fb_connect.js	(working copy)
@@ -55,10 +55,11 @@
     });
     // Facebook's invalid cookies persist if third-party cookies disabled.
     // Let's try to clean up the mess.
+    // @TODO: is this still needed with newer oauth SDK???
     FB_JS.deleteCookie('fbs_' + FB._apiKey, '/', ''); // app id
     FB_JS.deleteCookie('fbs_' + Drupal.settings.fb.apikey, '/', ''); // apikey
   }
-  if (FB.getSession()) {
+  if (FB.getUser()) { // @TODO: still needed with newer oauth SDK???
     // Facebook needs more time to log us out. (http://drupal.org/node/1164048)
     Drupal.settings.fb.reload_url = Drupal.settings.fb_connect.front_url;
     return false;
Index: fb.module
===================================================================
--- fb.module	(revision 3789)
+++ fb.module	(working copy)
@@ -147,6 +147,7 @@
     'xfbml' => FALSE,
     'status' => FALSE,
     'cookie' => variable_get(FB_VAR_USE_COOKIE, TRUE),
+    'oauth' => TRUE,
   );
 
   // Figure out which app the current request is for.
@@ -167,43 +168,11 @@
 
     if ($_fb) {
 
-      // Look for session info from several sources.
-      if ($session = $_fb->getSession()) {
-        // Learned session from cookie or signed request.
-        // Below, we store in our $_SESSION, just in case third-party cookies are not enabled.
-      }
-      elseif (isset($_REQUEST['fb_js_session'])) {
-        // Ajax callback via fb.js.
-        $_fb->setSession(json_decode($_REQUEST['fb_js_session'], TRUE));
-        $session = $_fb->getSession();
-      }
-      elseif (isset($_SESSION['fb'][$_fb_app->id]['session']) && arg(0) != 'logout') {
-        // Use the session previously stored.
-        $_fb->setSession($_SESSION['fb'][$_fb_app->id]['session']);
-      }
+      // @TODO: test this code with third party cookies disabled.
 
-      // Store session for future use.  We'll need it if third-party cookies
-      // disabled, or we are not using facebook's cookie.
-      if (isset($session) && variable_get(FB_VAR_USE_SESSION, TRUE)) {
-        $_SESSION['fb'][$_fb_app->id]['session'] = $session;
-      }
-
-      // Make javascript work even when third-party cookies disabled.
-      $fb_init_settings['session'] = $_fb->getSession();
-
-      // Sometimes when canvas page is open in one tab, and user logs out of
+      // @TODO: test if this is still true: Sometimes when canvas page is open in one tab, and user logs out of
       // facebook in another, the canvas page has bogus session info when
       // refreshed.  Here we attempt to detect and cleanup.
-      if (isset($session) && ($request = $_fb->getSignedRequest())) {
-        if (!isset($request['user_id']) ||
-            $request['user_id'] != $session['uid']) {
-          _fb_logout();
-          $_fb->setSession(NULL);
-          unset($session);
-          unset($_SESSION['fb'][$_fb_app->id]);
-          unset($fb_init_settings['session']);
-        }
-      }
 
       // Give other modules a chance to initialize.
       fb_invoke(FB_OP_INITIALIZE, array(
@@ -212,13 +181,13 @@
                 ));
 
       // See if the facebook user id is known
-      if ($fbs = $_fb->getSession()) {
+      if ($fbu = $_fb->getUser()) {
         fb_invoke(FB_OP_APP_IS_AUTHORIZED, array(
                     'fb_app' => $_fb_app,
                     'fb' => $_fb,
-                    'fbu' => $_fb->getUser(),
+                    'fbu' => $fbu,
                   ));
-        fb_js_settings('fbu', $_fb->getUser());
+        fb_js_settings('fbu', $fbu);
       }
       else {
         // Add perms to settings, for calling FB.login().
@@ -356,8 +325,8 @@
       return NULL;
     }
 
-    if (Facebook::VERSION >= "3") {
-      $message = 'This version of modules/fb is compatible with Facebook PHP SDK version 2.x, but %version was found.  Either upgrade modules/fb or downgrade %fb_platform.';
+    if (Facebook::VERSION < "3") {
+      $message = 'This version of modules/fb is compatible with Facebook PHP SDK version 3.x.y, but %version was found (%fb_platform).';
       $args = array('%fb_platform' => $fb_platform, '%version' => Facebook::VERSION);
       if (user_access('access administration pages')) {
         drupal_set_message(t($message, $args));
@@ -470,8 +439,7 @@
     $cache_key .= '_' . $fbu;
     // Get the user access token.
     if ($fbu == 'me' || $fbu == fb_facebook_user($fb)) {
-      $session = $fb->getSession();
-      $cache[$cache_key] = $session['access_token'];
+      $cache[$cache_key] = $fb->getAccessToken();
     }
     else {
       $session_data = fb_invoke(FB_OP_GET_USER_SESSION, array(
@@ -603,23 +571,25 @@
 
   $output .= "<script type=\"text/javascript\">\n";
   $output .= "<!--//--><![CDATA[//><!--\n";
-  $output .= "jQuery.extend(Drupal.settings, " . json_encode(array('fb' => fb_js_settings())) . ");\n";
+  $output .= "if (typeof(FB) == 'undefined') {\n";
+  $output .= "  jQuery.extend(Drupal.settings, " . json_encode(array('fb' => fb_js_settings())) . ");\n";
   $js_array = fb_invoke(FB_OP_JS, array('fb' => $GLOBALS['_fb'], 'fb_app' => $GLOBALS['_fb_app']), array());
   if (count($js_array)) {
     // The function we define in the footer will be called after FB is initialized.
-    $output .= "FB_JS.initHandler = function() {\n";
+    $output .= "  FB_JS.initHandler = function() {\n";
     //$output .= "debugger;\n";
-    $output .= implode("\n", $js_array);
-    $output .= "};\n";
-    $output .= "jQuery(document).bind('fb_init', FB_JS.initHandler);\n";
+    $output .= implode("\n  ", $js_array);
+    $output .= "  };\n";
+    $output .= "  jQuery(document).bind('fb_init', FB_JS.initHandler);\n";
   }
 
     // Load the JS SDK asynchronously.
   // http://developers.facebook.com/docs/reference/javascript/
-  $output .= "var e = document.createElement('script');\n";
-  $output .= "e.async = true;\n";
-  $output .= "e.src = Drupal.settings.fb.js_sdk_url;\n";
-  $output .= "document.getElementById('fb-root').appendChild(e);\n";
+  $output .= "  var e = document.createElement('script');\n";
+  $output .= "  e.async = true;\n";
+  $output .= "  e.src = Drupal.settings.fb.js_sdk_url;\n";
+  $output .= "  document.getElementById('fb-root').appendChild(e);\n";
+  $output .= "}\n\n";
 
   $output .= "\n//--><!]]>\n";
   $output .= "\n</script>\n";
@@ -699,9 +669,10 @@
 
     unset($_SESSION['fb'][$fb->getAppId()]);
     // Unsetting the javasript fbu can be helpful when third-party cookies disabled.
-    fb_js_settings('fbu', 0);
+    //fb_js_settings('fbu', 0); @TODO still needed? helpful?
 
     // Might as well try to clean up the mess.
+    // @TODO: Are facebook cookies renamed (fbsr_...)??? Is this even needed anymore???
     if (isset($_COOKIE['fbs_' . $fb->getAppId()])) {
       setcookie('fbs_' . $fb->getAppId(), '', time() - 42000, '/');
     }
@@ -721,9 +692,10 @@
   $GLOBALS['user'] = drupal_anonymous_user();
 
   // Unsetting the javasript fbu can be helpful when third-party cookies disabled.
-  fb_js_settings('fbu', 0);
+  //fb_js_settings('fbu', 0); @TODO still needed?? helpful???
 
   // Clean up facebook cookies.
+  // @TODO: Are facebook cookies renamed (fbsr_...)??? Is this even needed anymore???
   if (isset($GLOBALS['_fb_app'])) {
     if (isset($_COOKIE['fbs_' . $GLOBALS['_fb_app']->apikey])) { // still needed?
       setcookie('fbs_' . $GLOBALS['_fb_app']->apikey, '', time() - 42000, '/');
@@ -982,25 +954,28 @@
                                    'query' => $query,
                                  ));
         //dpm($result, "FQL " . $query); // debug
+        if (is_array($result))
+          foreach ($result as $data) {
+            $items[] = $data['uid2'];
+          }
+
+        // Facebook's API has the annoying habit of returning an item even if user
+        // has no friends.  We need to clean that up.
+        if (!$items[0])
+          unset($items[0]);
+
+        $cache[$fbu] = $items;
       }
       catch (Exception $e) {
         fb_log_exception($e, t('Failed call to fql.query: !query', array('!query' => $query)), $fb);
       }
 
-      if (is_array($result))
-        foreach ($result as $data) {
-          $items[] = $data['uid2'];
-        }
     }
-    // Facebook's API has the annoying habit of returning an item even if user
-    // has no friends.  We need to clean that up.
-    if (!$items[0])
-      unset($items[0]);
-
-    $cache[$fbu] = $items;
   }
 
-  return $cache[$fbu];
+  if (isset($cache[$fbu])) {
+    return $cache[$fbu];
+  }
 }
 
 // Return array of facebook gids
Index: fb_settings.inc
===================================================================
--- fb_settings.inc	(revision 3789)
+++ fb_settings.inc	(working copy)
@@ -111,9 +111,12 @@
 
   if (isset($sr['oauth_token'])) {
     fb_settings(FB_SETTINGS_TOKEN, $sr['oauth_token']);
-    $tokens = explode('|', $sr['oauth_token']);
-    if ($app_id = $tokens[0]) {
-      fb_settings(FB_SETTINGS_ID, $app_id);
+    if (!fb_settings(FB_SETTINGS_ID)) {
+      // Prefer app id learned from url rewriting over that learned from signed request (because sr may be encrypted).
+      $tokens = explode('|', $sr['oauth_token']);
+      if ($app_id = $tokens[0]) {
+        fb_settings(FB_SETTINGS_ID, $app_id);
+      }
     }
   }
 }
@@ -203,31 +206,6 @@
   // @TODO - somehow detect whether a signed request indicates canvas page or not.
   //fb_settings(FB_SETTINGS_TYPE, FB_SETTINGS_TYPE_CANVAS);
 }
-elseif (isset($_REQUEST['session'])) {
-  // New SDK's use session param for canvas pages.
-  // Deprecated!  'session' has been replaced with 'signed_request'.  This clause can go away.
-  $session = json_decode($_REQUEST['session'], TRUE);
-  fb_settings(FB_SETTINGS_TYPE, FB_SETTINGS_TYPE_CANVAS);
-  fb_settings(FB_SETTINGS_FBU, $session['uid']);
-  fb_settings(FB_SETTINGS_TOKEN, $session['access_token']);
-  // Which app?
-  $access_tokens = explode('|', $session['access_token']);
-  if ($app_id = $access_tokens[0]) {
-    fb_settings(FB_SETTINGS_ID, $app_id);
-  }
-}
-elseif (isset($_REQUEST['fb_js_session'])) {
-  // Ajax callback via fb.js.
-  $session = json_decode($_REQUEST['fb_js_session'], TRUE);
-  fb_settings(FB_SETTINGS_TYPE, isset($_REQUEST['fb_js_page_type']) ? $_REQUEST['fb_js_page_type'] : FB_SETTINGS_TYPE_CONNECT);
-  fb_settings(FB_SETTINGS_FBU, $session['uid']);
-  fb_settings(FB_SETTINGS_TOKEN, $session['access_token']);
-  // Which app?
-  $access_tokens = explode('|', $session['access_token']);
-  if ($app_id = $access_tokens[0]) {
-    fb_settings(FB_SETTINGS_ID, $app_id);
-  }
-}
 else {
   // We're not in a canvas page.
   // We might be in a facebook connect page.  We have to inspect cookies to make sure.
Index: fb_connect.module
===================================================================
--- fb_connect.module	(revision 3789)
+++ fb_connect.module	(working copy)
@@ -150,15 +150,12 @@
       // @TODO fb.module should have a helper to make this cleaner.
 
       $settings['fb_init_settings']['appId'] = $fb_app->id;
-      $settings['fb_init_settings']['session'] = $fb->getSession();
       fb_js_settings('apikey', $fb_app->apikey);
       fb_js_settings('fbu', fb_facebook_user($fb));
       fb_js_settings('fb_init_settings', $settings['fb_init_settings']);
-      //$js = drupal_add_js(array('fb' => fb_js_settings()), 'setting');
       // fb.module will add settings to footer.
     }
   }
-
 }
 
 
@@ -168,11 +165,11 @@
 function _fb_connect_block_login_defaults() {
   return array('anon_not_connected' => array(
                  'title' => t('Facebook Connect'),
-                 'body' => '<fb:login-button perms="!perms" v="2">Connect</fb:login-button>',
+                 'body' => '<fb:login-button scope="!perms" v="2">Connect</fb:login-button>',
                ),
                'user_not_connected' => array(
                  'title' => t('Facebook Connect'),
-                 'body' => '<fb:login-button perms="!perms" v="2">Connect</fb:login-button>',
+                 'body' => '<fb:login-button scope="!perms" v="2">Connect</fb:login-button>',
                ),
                'connected' => array(
                  'title' => t('Facebook Connect'),
Index: fb.install
===================================================================
--- fb.install	(revision 3789)
+++ fb.install	(working copy)
@@ -63,12 +63,12 @@
 
   if (class_exists('Facebook')) {
     $status['value'] = Facebook::VERSION;
-    if (Facebook::VERSION >= "3") {
-      $status['description'] = $t('Expected version 2.x.y of Facebook PHP SDK.');
+    if (Facebook::VERSION < "3" || Facebook::VERSION > "4") {
+      $status['description'] = $t('Expected version 3.x.y of Facebook PHP SDK.');
       $status['severity'] = REQUIREMENT_ERROR;
     }
     else {
-      $status['description'] = $t('Facebook PHP SDK loaded.');
+      $status['description'] = $fb_platform;
       $status['severity'] = REQUIREMENT_OK;
     }
   }
Index: contrib/fb_user_app.module
===================================================================
--- contrib/fb_user_app.module	(revision 3789)
+++ contrib/fb_user_app.module	(working copy)
@@ -71,7 +71,7 @@
       $fbu = fb_settings(FB_SETTINGS_FBU);
       // User has removed the app from their account.
       db_query("DELETE FROM {fb_user_app} WHERE apikey='%s' AND fbu=%d",
-        $fb_app->apikey, $fbu);
+               $fb_app->apikey, $fbu);
     }
   }
   elseif ($op == FB_OP_GET_USER_SESSION) {
@@ -118,11 +118,16 @@
 }
 
 /**
- * Keep track of when the user has visited the app, and whether they've
- * authorized the app or not.
+ * Keep track of when the user has visited the app.
  *
- * Historically this supported infinite sessions.  I believe if this data is
- * no longer necessary for the offline access extended permission.
+ * Historically we could learn a user's ID even if they hadn't authorized
+ * ("added") the app.  No longer the case, so all entries in fb_user_app
+ * should be for authorized users.
+ *
+ * A "signed request" should be fully-formed (have an oauth_token) on canvas
+ * pages, and on post authorize events (for as long as facebook continues to
+ * support them).  So this tracking will work best for canvas page apps and
+ * less reliably for connect.
  */
 function fb_user_app_track_user($fb, $fb_app) {
   // Coming from a user adding the app or a page adding the app?
@@ -134,35 +139,44 @@
     $fbu = $_REQUEST['fb_sig_page_id'];
   }
 
+  $sr = $fb->getSignedRequest();
+  watchdog('fb_user_app', __FUNCTION__ . " signed request is <pre>" . print_r($sr,1) . "</pre>"); // debug
 
-  // test if we are tracking only those apps that have been granted offline
-  // access.
-  $fb_session = $fb->getSession();
+  if (isset($sr['oauth_token'])) {
+    $access_token = $sr['oauth_token'];
+    $expires = $sr['expires'];
+    $fbu = $sr['user_id'];
+  }
+  else {
+    // @TODO: with new SDK, is there any useful tracking info?
+    return;
+  }
 
+
   // when 'expires' == 0 app has been granted offline access
   if ($fb_user_type == 'user' &&
-      $fb_session["expires"] <> 0 &&
-      variable_get(FB_USER_APP_VAR_USERS_THAT_GRANT_OFFLINE, FALSE))
+      $expires <> 0 &&
+      variable_get(FB_USER_APP_VAR_USERS_THAT_GRANT_OFFLINE, FALSE)) {
+    // Note, with new SDK, facebook provides 'expires' date even when user HAS GRANTED offline_access!
+    // @TODO: find some way to tell whether an access token will actually expire!
     return;
+  }
 
   // Track this event only if allowed to and only for users, not pages
   if ((variable_get(FB_USER_APP_VAR_TRACK_USERS, TRUE) && $fb_user_type = "user") ||
       (variable_get(FB_USER_APP_VAR_TRACK_PAGES, TRUE) && $fb_user_type = "page")) {
 
-    $session = $fb->getSession();
-    // Session key no longer useful, now store access token.
-    $access_token = isset($session['access_token']) ? $session['access_token'] : '';
     $result = db_query("UPDATE {fb_user_app} SET time_access=%d, session_key='%s', session_key_expires=%d, user_type='%s' WHERE apikey='%s' AND fbu=%d",
                        time(),
-                       $access_token, $session['expires'],
+                       $access_token, $expires,
                        $fb_user_type,
-                       $fb_app->apikey, fb_facebook_user($fb));
+                       $fb_app->id,
+                       $fbu);
 
     if ($result && !db_affected_rows()) {
       // The row for this user was never inserted, or it was deleted, or the times were the same.
-      $fbu = fb_facebook_user($fb);
       if ($fbu) {
-        //First make sure it was not just the same time
+        // First make sure it was not just the same time
         $result = db_query("SELECT * FROM {fb_user_app} WHERE apikey='%s' AND fbu=%d",
                            $fb_app->apikey,
                            $fbu);
@@ -176,7 +190,7 @@
                              $data['is_app_user'],
                              $fb_user_type,
                              $access_token,
-                             $session['expires'],
+                             $expires,
                              time(),
                              $data['proxied_email'],
                              0 // time_cron
@@ -203,7 +217,7 @@
     $mail = $data->proxied_email;
   }
 
-  if (!$mail) {
+  if (!isset($mail) || !$mail) {
     // Ask facebook for info.
     $fb = fb_api_init($fb_app);
     $info = fb_users_getInfo(array($fbu), $fb);
Index: README.txt
===================================================================
--- README.txt	(revision 3789)
+++ README.txt	(working copy)
@@ -20,8 +20,8 @@
 
 To install:
 
-- Make sure you have a PHP client from facebook (version < 3.0.0).
-  The 3.0.0 or higher versions are not supported by this version of Drupal for Facebook.
+- Make sure you have a PHP client from facebook (version >= 3.1.1).
+  The 2.x.y versions are not supported by this version of Drupal for Facebook.
   Download from http://github.com/facebook/php-sdk.
   Extract the files, and place them in sites/all/libraries/facebook-php-sdk.
 
@@ -29,10 +29,10 @@
   another recognised location (such as sites/all/libraries), providing that the
   directory is named 'facebook-php-sdk'.
 
-  Or, to manually set the location of the php-sdk in any other directory, edit
-  your settings.php to include a line similar to this (add to the section where
-  the $conf variable is defined, or the very end of settings.php. And
-  customize the path as needed.):
+  Or, to manually set the location of the php-sdk in any other
+  directory, edit your settings.php to include a line similar to the
+  one below. Add to the section where the $conf variable is defined,
+  or the very end of settings.php. And customize the path as needed.
 
   $conf['fb_api_file'] = 'sites/all/libraries/facebook-php-sdk/src/facebook.php';
 
