How to use Facebook OAuth 2.0 authentication like Zynga and other use it? - redirect

I want to display the "Request for Permission" box directly when the user enters http://apps.facebook.com/myfancyapp. The Facebook Authentication documentation is pretty clear on how the URL have to look like
https://graph.facebook.com/oauth/authorize?client_id=[APPID]&redirect_uri=http://www.myfancyapp.com/&scope=user_photos,user_videos,publish_stream
Pasting this URL directly into the browser works like it should. What I want is to redirect the user via JavaScript (or something else) from the application URL
http://apps.facebook.com/myfancyapp
to the authentication box URL above.
I thought something like this would work:
<script type="text/javascript">
<!--
window.location = "https://graph.facebook.com/oauth/authorize?client_id=[APPID]&redirect_uri=http://www.myfancyapp.com/&scope=user_photos,user_videos,publish_stream"
//-->
</script>
This redirects me to a page with a body that looks like this
Clicking on the image/test then redirects to the authentication box.
How can I directly redirect to the "Request for Permission" box. I know it works somehow as other developers (Zynga for example) already do it.

I'm doing the same thing as the asker, only instead of window.location, use top.location.href = "https://graph....."
Like:
<script type="text/javascript">
top.location.href = "https://graph.facebook.com/oauth/authorize?client_id=[APPID]&scope=email&redirect_uri=http://apps.facebook.com/myfancyapp/";
</script>
Prompts for login if needed, and then permissions. Then redirects to the app.

Doing this with PHP is a cinch.
On the backend
$facebook = new Facebook( array(
'appId' => '<FB_APP_ID>'
, 'secret' => '<FB_APP_SECRET>'
, 'cookie' => true
));
$fbSession = $facebook->getSession();
if ( !$fbSession )
{
$url = $facebook->getLoginUrl( array(
'canvas' => 1
, 'fbconnect' => 0
, 'display' => 'page'
, 'cancel_url' => null
, 'req_perms' => 'user_photos,user_videos,publish_stream'
) );
}
And then, on the frontend
<script type="text/javascript">
top.location.href = '<?php echo $url; ?>';
</script>
<p>
Not being redirected? Click Here.
</p>

Related

Detect Like with Facebook JavaScript API + iFrame

Building an app with the Facebook JavaScript API that will embedded into a page using the new iframe method.
I want to detect if they have liked the current page. Usually I would use print_r($_REQUEST) in PHP but that doesn't seem to work when using an iframe.
There is also this option: http://developers.facebook.com/docs/reference/fbml/visible-to-connection/ but it says its deprecated and I have never liked this method as its fairly hacky.
What is the way t do it now? Prefer to use XFBML + JavaScript API but can use PHP if required.
We've done this several times, and it seems to work pretty well. It uses XFBML to generate a Like Button widget and the JS SDK to render XFBML and subscribe to Facebook events. Code sample below:
edit: Since you're looking to detect if the user is a fan when the page loads, and FB deprecated the feature to let you get it directly from them when the canvas is loaded by passing fb_page_id to the address query string, you'll need an application install for the user to test their fan-dom of your page. It certainly adds a lot of friction to your application, but it is what it is for now - I guess.
<?php
require 'facebook.php';
// Create our Application instance (replace this with your appId and secret).
$facebook = new Facebook(array(
'appId' => 'YOUR APP ID',
'secret' => 'YOUR APP SECRET',
'cookie' => false,
));
try
{
$session = $facebook->getSession();
if (empty($session['uid']))
{
throw new Exception("User not connected to application.");
}
$is_fan = $facebook->api(array(
'method' => 'fql.query',
'query' => "SELECT uid, page_id FROM page_fan WHERE uid = {$session['uid']}"
));
if (false == $is_fan || count($is_fan) == 0) // 0 results will be returned if the user is not a fan
{
$is_fan = false;
}
else
{
$is_fan = true;
}
}
catch (FacebookApiException $e)
{
/**
* you don't have an active user session or required permissions
* for this user, so rdr to facebook to login.
**/
$loginUrl = $facebook->getLoginUrl(array(
'req_perms' => 'user_likes'
));
header('Location: ' . $loginUrl);
exit;
}
?>
<html>
<head>
</head>
<body>
<? if (empty($is_fan)): //user is not a fan. ?>
<fb:like href="http://www.facebook.com/your-facebook-page"
show_faces="true"
width="400">
</fb:like>
<? else: ?>
Yay! You're a fan!
<? endif; >?
<div id="fb-root"></div>
<script src="http://connect.facebook.net/en_US/all.js" type="text/javascript">
</script>
<script type="text/javascript">
FB.init({
appId: '<?= FB_APP_ID; ?>',
cookie: true,
status: true,
xfbml: true
});
// Subscribe to the edge creation event, from Facebook
FB.Event.subscribe('edge.create', function(response)
{
alert("Congratulations! We are so excited that you are a fan now! woot!")
});
</script>
</body>
</html>
okay, finally got got everything formatted with straight markdown. that wasn't painful at all.. (sike) :|

Asking for facebook permissions only when required

I have the following script which works, i.e. it goes to the facebook login page if the user is not already logged in, and asks them if they are ok with the app to post messages on their wall:
<?php
require 'facebook.php';
$facebook = new Facebook(array(
'appId' => 'removed for security reasons',
'secret' => 'removed for security reasons',
'cookie' => true,
));
$session = $facebook->getSession();
if ($session) {
if (isset($_GET[id])) {
$post = $facebook->api("/" . $_GET['id'] . "/feed", "POST", array('message' => 'Hello!'));
echo 'A message has been posted on your friends wall';
} else {
$friends = $facebook->api('/me/friends');
foreach ($friends as $key=>$value) {
echo 'You have ' . count($value) . ' friends<br />';
foreach ($value as $fkey=>$fvalue) {
echo 'friend id = ' . $fvalue[id] . ' - friend name = ' . $fvalue[name] . ' - post message<br />';
}
}
}
} else {
$loginUrl = $facebook->getLoginUrl(array(
'req_perms' => 'publish_stream',
'next' => 'http://'.$_SERVER['SERVER_NAME'].'/stage1.php',
'cancel_url' => 'http://'.$_SERVER['SERVER_NAME'].'/cancel.php',
));
header('Location: '.$loginUrl);
}
?>
How can this be improved so it does not ask for extended permissions in the start. It should only ask for basic permissions to display the friends list, and only ask for extended permissions if the user clicks on the friend to post a message.
Here's a rewrite of your code, with what I think are best practices:
<?php
require 'facebook.php';
$facebook = new Facebook(array(
'appId' => 'removed for security reasons',
'secret' => 'removed for security reasons',
'cookie' => true,
));
$session = $facebook->getSession();
// Prepare the login url with the right permission
$loginUrl = $facebook->getLoginUrl(array(
'req_perms' => 'publish_stream',
'next' => 'http://'.$_SERVER['SERVER_NAME'].'/stage1.php',
'cancel_url' => 'http://'.$_SERVER['SERVER_NAME'].'/cancel.php',
));
if ($session) {
try {
// Before processing the request
// check if we got the right permission
$perms = $facebook->api(array(
"method" => "fql.query",
"query" => "SELECT publish_stream FROM permissions WHERE uid=me()"
));
if($perms[0]['publish_stream']==='1') {
// We have the right permission
if (isset($_GET['id'])) {
// A small security measure
$id = (int) $_GET['id'];
$post = $facebook->api("/$id/feed", "POST", array('message' => 'Hello!'));
echo 'A message has been posted on your friends wall';
} else {
$friends = $facebook->api(array(
"method" => "fql.query",
"query" => "SELECT uid,name FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1=me())"
));
foreach($friends as $friend)
echo "friend id = {$friend['uid']} - friend name = {$friend['name']} - post message<br />";
}
} else {
// We don't have the right permission
header('Location: '.$loginUrl);
}
} catch (FacebookApiException $e) {
error_log($e);
}
} else {
header('Location: '.$loginUrl);
}
?>
How to check for a permission is explained here. Also I've added comments to save writing an explanation.
Quickly, there is something I want to point out regarding the following block of code:
foreach ($friends as $key=>$value) {
echo 'You have ' . count($value) . ' friends<br />';
foreach ($value as $fkey=>$fvalue) {
echo 'friend id = ' . $fvalue[id] . ' - friend name = ' . $fvalue[name] . ' - post message<br />';
}
}
Your 1st foreach loop is really misleading and not good practice at all. The Graph API isn't overly consistent in how it presents data, but the reason you are doing the foreach is to deal with the data key in the JSON object that is returned. This is generally a bad idea, because that data key is typically present along with other keys (like paging). Instead, I would check to see that $friends['data'] is not empty, and then re-assign the $friends array like so: $friends = $friends['data'];.
Example:
if (!empty($friends['data']))
{
$friends = $friends['data'];
}
else
{
$friends = array();
}
now, for your question.
You mentioned that you don't want to over-ask for permissions. That's a great thing to want, but the problem with it is that Facebook doesn't make it exceedingly easy to check for which permissions you do have or do not have. There is an FQL table that allows you check if your user has a certain set of permissions, but this table doesn't get updated with any kind of urgency. If you obtain extra permissions from a user (or if a user retracts permissions) and you then check this FQL table for the status of the permission, it can (and probably will) read the incorrect value and you will get a false positive.
You have three options to deal with this, that I can think of right off the top of my head.
Continue on your stage1.php code, as you are - there's nothing wrong with the way you're obtaining the installation and the session for the user there. You change page 2 to redirect your user through the OAuth endpoint requesting the publish-stream permission every time the user loads the page. The OAuth endpoint will not re-prompt the user to install, and will send them on their way.
The cons with this approach is, every request to post to a friends' wall turns into 3 requests.
The initial page load
The OAuth redirect / load
The redirect from OAuth back to your application
This approach also requires that you add a flag to your next key in your loginURL, which you can look for to make sure the user went through the OAuth endpoint, otherwise you're going to get an infinite redirect error.
Utilize the FB Javascript SDK to check for your users' current set of permissions. To do this, you'll utilize the FB.getLoginStatus method.
Example:
<div id="fb-root"></div>
<script src="http://code.jquery.com/jquery-1.5.2.min.js"
type="text/javascript" charset="utf-8">
</script>
<script src="http://connect.facebook.net/en_US/all.js"
type="text/javascript" charset="utf-8">
</script>
<script type="text/javascript">
(function($)
{
FB.init({
appId: '<?= FB_APP_ID; ?>',
cookie: true,
status: true,
xfbml: true
});
$('a').click(function(event)
{
var self = this;
event.preventDefault();
FB.getLoginStatus(function(session)
{
if (session.perms.match(/\"publish_stream\"/))
{
/* This user has publish stream, so we don't need
* to ask again
**/
window.location = $(self).attr('href');
}
else
{
/* This user does not have publish stream, so we need
* to ask.
**/
FB.login(function(response)
{
if (response && response.perms.match(/publish_stream/))
{
/* We now have publish stream access! */
window.location = $(self).attr('href');
}
}, {
perms: 'publish_stream'
});
}
})
return false;
})
})(jQuery);
Don't utilize any extended permissions, use the Javascript SDK (again) and give the user a publish-dialog for each user they would like to publish on the wall of. This is a relatively easy thing to do, also.
Example:
given your links for users:
Friend 1
Friend 2
Friend 3
You can do something like this:
<div id="fb-root"></div>
<script src="http://code.jquery.com/jquery-1.5.2.min.js"
type="text/javascript" charset="utf-8">
</script>
<script src="http://connect.facebook.net/en_US/all.js"
type="text/javascript" charset="utf-8">
</script>
<script type="text/javascript">
(function($)
{
$('a').click(function(event)
{
var user_id = $(this).data('id');
FB.ui({
method: 'feed',
message: 'Hello!',
to: user_id
}, function(response)
{
//this gets called whether it was successful, or not.
})
});
})(jQuery);

Problem at first time going to facebook app

What I am having problem is that when a user first time login to this facebook iframe app then he is sent to a blank page with a facebook logo. Followin is screen shot.
Following is my code, I am using new PHP Sdk:
$facebook = new Facebook(array(
'appId' => 'xxxxxxxxx',
'secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'cookie' => true,
));
$this->facebook=$facebook;
$this->session = $facebook->getSession();
$this->me = null;
// Session based API call.
if(!$this->session){
if (!$this->session) {
//echo $loginUrl = $facebook->getLoginUrl($par);
$loginUrl = $facebook->getLoginUrl(
array(
'canvas' => 1,
'fbconnect' => 0,
'display' => 'page',
'req_perms' => 'email,publish_stream,status_update,user_birthday,user_location,user_work_history'
));
$this->request->redirect($loginUrl);
}
}
if ($this->session) {
try {
$this->uid = $facebook->getUser();
$this->user = $facebook->api('/me');
} catch (FacebookApiException $e) {
error_log($e);
}
}
don't redirect to the loginUrl, what you are essentially doing is making your iframe goto a facebook page resulting in facebook in an iframe of facebook. and facebook does not display inside an iframe. so the auth page is not shown.
you need to do a top level redirect. basically redirecting the entire page, not just your iframe. one way to do top level redirect from inside an iframe is to show the following javascript:
<html><head>
<script type="text/javascript">
window.top.location.href = "<your redirect url here>";
</script>
<noscript>
<meta http-equiv="refresh" content="0;url=<your redirect url here>" />
<meta http-equiv="window-target" content="_top" />
</noscript>
</head></html>

facebook iframe app problem.... opens on server not in facebook frame

I'm very new to facebook platform.
I developed an iframe app. which after allowing permsiions, opens the application on my server and not in facebook iframe.
I hope i'm clear. I'm using $user = $facebook->require_login().
I read somewhere that adding $facebook->require_frame() would help but it didn't help.
The page reloads with new access token on each reload.
Someoe please help me.
Thanks in advance
Can you post some of the code you're using for the redirect?
If you use $facebook->GetLoginUrl to construct the Auth URL, the code should look like this -
$loginUrl = $facebook->getLoginUrl(array('canvas' => 1,
'fbconnect' => 0,
'req_perms' => 'permissions_here',
'next' => $canvas_base_url . 'index.php',
'cancel_url' => $canvas_base_url
));
In the Array, define your post authentication URL in 'next'. You should build it using the URL structure of http://apps.facebook.com/CANVASURL/yourpostauthpage.php.
In my snippet, I've created a variable ($canvas_base_url) to store my base URL.
my code is
<?
$api_key = 'xxxxxxxxxxxx';
$secret = 'xxxxxxxxxxxxx';
$appcallbackurl = 'http://www.phonecurry.com/fbapp/';
include_once 'facebook.php';
$facebook = new Facebook($api_key, $secret);
$user = $facebook->require_login();
try
{
if(!$facebook->api_client->users_isAppUser())
{
?>
<script language="JavaScript">
<!--
window.location = "http://www.facebook.com/login.php?v=1.0&api_key=xxxxxxxxxxxxx&next=http%3A%2F%2Fapps.facebook.com%2Fmycanvasapp%2F&canvas&req_perms=publish_stream";
</script>
<?php
}
}
catch (Exception $ex)
{
$facebook->set_user(null, null);
$facebook->redirect($appcallbackurl);
}
$has_permission = $facebook->api_client->users_hasAppPermission("publish_stream");
if(!$has_permission)
{
?>
<script language="JavaScript">
<!--
window.location = "http://www.facebook.com/login.php?v=1.0&api_key=xxxxxxx&next=http%3A%2F%2Fapps.facebook.com%2Fmycanvasapp%2F&canvas&req_perms=publish_stream";
</script>
<?php
}
?>

iFrame App. Permissions Request?

I want to request permissions when the user first clicks my iFrame Facebook application. The problem is the examples I have seen force the user to click a button to load the http://www.facebook.com/authorize.php URL.
Is there a way to iframe the authorize.php page in my application? I've seen it done before but can't find out how.
If I currently try it, it shows the "go to facebook box". The method I seen changes the href or something on the browser.
Any ideas?
I do something like this in one of my iframe applications (I've simplified the actual code for this example)
$fbSession = $facebook->getSession();
if ( $fbSession )
{
$url = $facebook->getLoginUrl( array(
'canvas' => 1
, 'fbconnect' => 0
, 'req_perms' => 'list,of,perms'
, 'display' => 'page'
) );
include( 'redirect.php' );
exit;
}
Then, redirect.php
<script type="text/javascript">
top.location.href = '<?php echo $url; ?>';
</script>
<p>
Not being redirected? Click Here.
</p>
no need to complicate: target="_top" is the answer!
Best!
m