Authenticated Referrals for Facebook Apps

Facebook no longer supports authenticated referrals, but this code will still work for App Center pages and links from bookmarks, etc.

Have you ever seen a link in your Facebook feed that says a friend just read an article on a website, and then when you click that link it asks you to Facebook authenticate before you even see the website? That’s called authenticated referrals.

I’m personally not a big fan of them as it seems a poor user experience. I think it’s nicer to let the user  first see a site before presenting them with an authentication dialog and asking then for their personal data. Nevertheless, this is required for apps in the App Center, so we better support it.

Setting Up Authenticated Referrals

Setting up an app to use authenticated referrals is easy. Just go into the app’s setting and click “permissions” in the left menu. On that form check “enabled” for “authenticated referrals” and add the permissions you want. In this case, we’ll add the same default permissions as the Birthday app which are email and friends_birthday.

Framework for Authenticated Referrals

For web and mobile apps, a request from an authenticated referral will have ?code=… added to the query string. This is the same code we get passed to our redirect page, so all we have to do is send it to the redirect page. The redirect uri needed to exchange the code for the token will be the current url up unitl the code parameter.

Canvas apps are trickier. There’s no way to know if a request came from an authenticated referral. What we’ll need to do is check to see if the user is authorized but not in the database. If so, we’ll send them to the redirect page. If they are in the database, we’ll set a cookie, so we don’t have to check again.

We can add this code to initFacebookApp in /lib/appfraework.php.

function initFacebookApp($requireauth=false,$additionalpermissions=false) {

    // same code as before here

    // authenticated referrals
    if ($GLOBALS['apptype'] == "canvas") {
        // canvas apps, if authrorized, check for the cookie
        $cookiename = "initialized_".$GLOBALS['facebookAppId']."_".$facebookapp->userId;
        if ($authorized && (stripos($_SERVER['REQUEST_URI'],$GLOBALS['facebookRedirectPage']) === false) && (!isset($_COOKIE[$cookiename]))) {
            // no cookie, check if user is in db
            $initialize = true;
            $sql = "select userid from user where userid='".$db->real_escape_string($facebookapp->userId)."'";
            $result = $db->query($sql);
            if ($row = $result->fetch_assoc()) {
                $initialize = false;
            }
            if ($initialize) {
                // user came from authenticated referral, so send to redirect page to initialize
                $success_uri = substr($_SERVER['REQUEST_URI'],strrpos($_SERVER['REQUEST_URI'],"/")+1); 
                setcookie ("success_uri",$success_uri,0,"/");
                $url = $facebookapp->getCanvasUrl($GLOBALS['facebookRedirectPage']."?code=1"); // need to add code so the page works
                doRedirect($url);
            } else {
                // user is in db, so set cookie
                setcookie ($cookiename,"1",0,"/");
            }
        }
    } else {
        // web and mobile apps will get ?code= from link, send to rediret page
        if (isset($_GET['code']) && (stripos($_SERVER['REQUEST_URI'],$GLOBALS['facebookRedirectPage']) === false) && ($_GET['fb_source'] != "notification")) {
            $successuri = $_SERVER['SCRIPT_URI'];
            $delimiter = "?";
            foreach ($_GET as $key=>$val) {
                if ($key == "code") {
                    break;
                } else {
                    $successuri .= $delimiter.$key."=".rawurlencode($val);
                    $delimiter = "&";
                }
            }
            setcookie ("success_uri",$successuri,0,"/");
            $url = $GLOBALS['webRedirectUrl']."?redirecturi=".rawurlencode($successuri)."&code=".rawurlencode($_GET['code']);
            doRedirect($url);
        }
    }

    return $authorized;
}

We’ll have to make a little change to /birthday/redirect.php to look for the redirecturi parameter.

    // if web or mobile, exchange code for token
    if ($GLOBALS['apptype'] != "canvas") {
        if (isset($_GET['redirecturi'])) $redirecturi = $_GET['redirecturi'];
        else $redirecturi = $GLOBALS['webRedirectUrl'];
        $authorized = $facebookapp->setAccessTokenFromCode($_GET['code'],$redirecturi);
    }

Download the Files for this Post