I'm attempting to use the new Graph API Facebook recently released, but I can't seem to get it to work correctly.
I've gone through the steps, and after the /authorize call, I receive an access_token:
access_token=109002049121898|nhKwSTJVPbUZ5JYyIH3opCBQMf8.
When I attempt to use that token I get:
{
"error": {
"type": "QueryParseException",
"message": "An active access token must be used to query information about the current user."
}
}
I'm stumped as too why...
-AC
When using your Facebook Application's token
If you're using the me alias as in https://graph.facebook.com/me/ but your token is acquired for a Facebook Application, then "me" isn't you anymore - it's the app or maybe nothing. Anyway, that's not your intention for the app to interact with itself.
In this case you will want to interact with your personal user account from an app. What you need to do (after giving the app the permissions it requests in the UI when it asks) is find your facebook userid # and put it in place of "me" to access your own info. e.g. Mark Zuckerberg's facebook userid is 4 so he is https://graph.facebook.com/4/
The alias me only works if you're you! Sometimes it's hard to remember who the current user is when programming facebook (i.e. you, the Page, the App, etc) because we're accustomed to using the facebook UI as ourselves most of the time. From a programming standpoint it depends on what the acquired token represents.
A great blog post that always helps correct me is Ben Biddington | Facebook Graph API — getting access tokens.
same thing here. I followed Ben Biddington's blog to get the access token. Same error when trying to use it. Facebook's OAuth implementation doesn't follow the spec completely, i am fine with it as long as the doc is clear, which obviously is not the case here. Aslo, it would be nice if the userid and username are returned with the access token.
Just to clarify -- after you call
https://graph.facebook.com/oauth/authorize?
you should receive a CODE which, in conjunction with your CLIENT_ID and CLIENT_SECRET (assuming you have registered your application) can be exchanged for an access_token at
https://graph.facebook.com/oauth/access_token?
If this is indeed how you came by your ACCESS_TOKEN, you should then be able to request
https://graph.facebook.com/me/
Adding type parameter returns the auth_token for the application level, so it is better to OMIT it. What worked for me, after countless attempts and combinations, is using the same redirect_url parameter in the call to /oath/access_token as was used in the call to /oath/authorize.
So the full sequence to authorize your app on someone's behalf is:
1. call or redirect to:
"https://graph.facebook.com/oauth/authorize?client_id=" + my_clientId + "&scope=publish_stream,offline_access,manage_pages" + "&redirect_uri=" + "http://my_redirect_url?blah"
2. in the page located at the return_url above, issue a request or what ever else to this url:
"https://graph.facebook.com/oauth/access_token?client_id=" + client_id + "&client_secret=" + secret + "&code=" + Request.QueryString["code"] + "&redirect_uri=" + "http://my_redirect_url?blah"
I've been having the exact same problem. A couple of things I've done to resolve it:
Try it all out in the browser first to make sure the urls are correct at each stage
Ensure the redirect url is identical, not just equivalent. Parameters in the same order, encoding the same
Don't use the type=client_cred, or anything else for that matter
Encode any ampersands in the redirect_url (but not the rest of the url) e.g. http://example.com/fb?foo=234%26bar=567. This one caused me the most issues. When the callback page was run, only the url before the first ampersand was included, as the ampersand was assumed to be part of the url for graph.facebook.com, not part of the redirect_url. I was then getting the values from the querystring to put in the redirect_url for the second call, but they weren't there. Once I encoded the ampersands they appeared correctly.
Don't have any empty values in you encoded querystring parameters (e.g. ?foo=%26bar=123)
I want to point out what has sort of been said on Ben Biddington's blog, and what I noticed from looking at the "malformed" access_token in the initial question. Others have said similar things in this thread, but I want to be explicit.
The token is not actually malformed, but rather a token that allows you to do actions on behalf of the APP, not the user. This is the token you'd use if you wanted to get all of the users of the app, or view insights for your app, etc, with the requests typically coming from your server, not the client. This type of token is gained by using the type=client_cred parameter. If you want to do things on behalf of the user, do not specify type=client_cred, and make sure you specify the following parameters in your call to http://graph.facebook.com/oauth/access_token:
'client_id' => APP_ID
'redirect_uri' => REDIRECT_URI
'client_secret' => APP_SECRET
'code' => $_GET['code']
I've written this as key-value pairs of a PHP array, but I think you get the point. The code GET value is gained after making the initial call to http://graph.facebook.com/oauth/authorize with the following parameters:
'client_id' => APP_ID
'redirect_uri' => "http://your.connect.url/some/endpoint"
I hope this helps! What the Facebook docs say, but don't say well, is that getting an access_token is a two-request process.
I actually noticed that if your return uri doesn't have a slash on the end you have issues. I'm currently testing in the browser and return_uri=https://mydomain.com doesn't work but return_uri=https://mydomain.com/ does work. If I use the first I get "Error validating verification code."
This seems a bit odd, but I prolly just missed a word in the spec/instructions some where. Did lose two hours of my life to it though.
I had the same problem, but getting rid of type=client_cred and making sure that the redirect_uri parameter is the same when making the authorize and the access_token call fixed the issue.
I had the same issue in IE8 only.
The solution for me was sending the access_token in the API request.
Something like this:
FB.api('/me/friends?access_token=<YOUR TOKEN>
I obtained my token through PHP like this:
// Create our Application instance.
$facebook = new Facebook(array(
'appId' => '<API_ID>',
'secret' => '<SECRET>',
'cookie' => false,
));
$session = $facebook->getSession();
$token = $session['access_token'];
Related
I have a Page Tab facebook app. I want to post to users timeline from it.
After login on client side with javascript sdk (I use angularjs module for that Ciul/angular-facebook (sorry, cannot post github link here)):
https://gist.github.com/Sevavietl/7e363fdfd0e714a12a43
I retrieve access_token on server side and trying to post a carousel to the users feed:
https://gist.github.com/Sevavietl/cec5fa434837312adfd3
I have two problems:
While first call I get
Graph returned an error: (#210) Param id must be a page.
After browsing, I found that this can be caused by wrong token usage. Not user_access_token. But I login the user on the client side.
And for next calls I get
Graph returned an error: This authorization code has been used.
Again, after browsing, I found that token can be used only once in order to be OAuth compliant.
Please, advise me how to do this right?
Thank you in advance.
Best regards,
Vsevolod
After spending some time on this, I am writing my solution, as it was not really obvious, at least for me. But, actually, all info is present in the documentation.
Starting with problem number 2: And for next calls I get Graph returned an error: This authorization code has been used.
As it was mentioned in the comments, I indeed was confusing access_token with authorization code. As I understand in really simplified form, the mechanism is:
When you login with facebook-javascript-sdk it writes authorization code to cookies.
Then on the server side you can retrieve access_token from javaScriptHelper available in facebook-php-sdk. This helper has getAccessToken() method, which retrieves access_token using authorization code from cookies. This is the place where I was confused. I was trying to use getAccessToken() on every request. As requests were made with AJAX the authorization code was not changed, and as you can use it only once I was getting an error. The solution to this was pointed in many places on the Internet, but somehow I was able to misunderstand this.
Here is the code excerpt that uses sessions to store access_token, and uses getAccessToken() method only if access_token is not set in the session.
$fb = new Facebook([
'app_id' => $widget->app_id,
'app_secret' => $widget->app_secret,
'default_graph_version' => 'v2.5',
]);
$helper = $fb->getJavaScriptHelper();
if ($request->session()->has('facebook_access_token')) {
$accessToken = $request->session()->get('facebook_access_token');
} else {
$accessToken = $helper->getAccessToken();
// OAuth 2.0 client handler
$oAuth2Client = $fb->getOAuth2Client();
// Exchanges a short-lived access token for a long-lived one
$longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($accessToken);
$request->session()->put('facebook_access_token', (string) $longLivedAccessToken);
$request->session()->save();
}
if ($accessToken) {
$fb->setDefaultAccessToken($accessToken);
} else {
die('No Access Token');
}
I use Laravel, so the session handling is not framework agnostic. This code is only for example, it is better to create service and move logic there.
Now. About the first problem: While first call I get Graph returned an error: (#210) Param id must be a page.
Again I was confusing two things '{user-id}/feed' and '{page-id}/feed'. My aim was to post a carousel with images and links. To create a carousel you have to provide child_attachments in the fields array. While you can send a Post like this to '{page-id}/feed', you cannot do so for '{user-id}/feed'. So at the moment you cannot post a carousel to users feed.
So when Graph Api was getting a Post data applicable for '{page-id}/feed', it was assuming that I have passed the {page-id}. And when getting the {user-id} instead, the Graph Api yelled back "(#210) Param id must be a page.".
This question has been asked a few times on Stack, but there have been no real answers. Let me try to explain my situation anyways.
We use an application that uses Facebook OAuth2 login. This login used to work fine till last week, and all of a sudden it is troubling us now.
Application Flow:
Step 1: User presses login with Facebook button on our website
Step 2: Redirected to Facebook login/authorization page
Step 3: On authorizing the app, the callback comes to our application, with a short lived "code" param.
Step 4: This "code" param would be exchanged for a 60 day Access token using "https://graph.facebook.com/oauth/access_token" URL.
Error in Step 4:
When we try to exchange the short living "code" for the access token, we get this error from Facebook.
{"error":{"message":"This authorization code has been used.","type":"OAuthException","code":100}}
Observation:
For users who are newly coming to the application, the above-said error does not occur.
For a returning user this call fails with the above-said error.
Our application is live for more than 9 months now, and this error has come only in the past 7-10 days. We have had thousands of users using it successfully prior to that.
What I already got from Forums:
Here is my interpretation of what I read. May be inaccurate.
Facebook has some weird policy that necessitates the app developer to maintain the temporary 10 minute code until the 60 day code that was obtained during the first login expires. So we should create a cookie with the Access token on the user's browser. I was even able to see people modifying their code in order to create the cookies.
What's really bothering me?
The suggested solutions assumes that the cookie that they create would be present in the user's browser always. This is a bad assumption to make, as the cookie may be erased at any time.
I have another app Id/app secret that I use for my development (i.e localhost), and that works perfectly. The login happens fine out there, But its only the product machine that has the problem.
This problem didn't happen on the production machine for nearly 10 months since we launched the app, and it has come all of a sudden. Worst of all, I am unable to get any record of recent changes that breaks this flow.
Edit:
Platform: Python, Google Appengine. We do not use any Facebook SDKs, we make direct HTTP Calls to all the login URLs.
Call that fails : https://graph.facebook.com/oauth/access_token - we are passing the appId, secret and code (obtained from facebook) within 20 seconds of the first call happening.
Hope there is enough information here to show that our code is not totally incorrect. Any tips/pointers from people who have encountered and solved this problem is Welcome. If its a Facebook bug, and the Facebook dev comes to notice, I would be even happier.
I got round this issue by using a random GUID which is appended to each callback url i pass into facebook. It seems the code that facebook returns is made up of a few parts including the redirect_uri parameter you have to specify. By using this GUID trick, your app continues to work but facebook thinks it's a different URL hence generating a new code.
If you store that GUID in a temporary session, it's always the same. Here's a very cut down version of what I mean. I'm using C# but the solution will be the same:
Before i start the oauth process:
Session["facebook_buster"] = System.Guid.NewGuid().ToString();
Then to kick off the login:
var facebook = new FacebookClient();
var loginUrl = facebook.GetLoginUrl(new
{
client_id = ...,
redirect_uri = ..."/facebook/oauthcallback?buster=" + Session["facebook_buster"].ToString(),
display = "popup",
scope = "publish_stream,user_photos"
});
And then in my callback method, when I want to exchange that code for a new access_token:
var facebook = new FacebookClient();
dynamic result = facebook.Post("oauth/access_token", new
{
client_id = ...,
client_secret = ...,
redirect_uri = ..."/facebook/oauthcallback?buster=" + Session["facebook_buster"].ToString(),
code = Request["code"] // this is the returned code from the first method
});
Note in that second method i'm using the same session key so that the authorization code is successful.
Been testing this all morning by revoking permissions / manually changing my stored access_token (in my db) / removing my stored access_token completely and it works every time.
Hope this helps!
I struggled with this today for a while too. Not sure if you're using the Facebook PHP class (from what you wrote, it seems you don't), however, it could be a pointer anyways - the problem was that the Facebook PHP library seems to obtain the token from the code automatically and I was trying to do it again.
BASIC PROBLEM: I want my app to be able to make calls to the Facebook graph api about authorized users even while the user is away.
For example, I want the user (A) to authorize the app, then later I want user (B) to be able to use the app to view info about user (A)'s friends. Specifically: the "work" field. Yes, I am requesting those extended permissions (user_work_history, friends_work_history, etc). Currently my app has access to the logged-in user's friends work history, but not to any of the friends' work history of other users of the app.
Here's what I know already:
Adding offline_access to the scope parameter is the old way and it
no longer works.
The new way is with "long-lived" access tokens,
described here. These last for 60 days.
I need to exchange a normal access token to get the new extended token. The FB documentation says:
https://graph.facebook.com/oauth/access_token?
client_id=APP_ID&
client_secret=APP_SECRET&
grant_type=fb_exchange_token&
fb_exchange_token=EXISTING_ACCESS_TOKEN
Here's what I don't know (and I'm hoping you can tell me):
How do I get the extended (aka "long-lived") access token using the Facebook PHP SDK? Currently, my code looks like this:
$facebook->getAccessToken();
Is there such a thing as this?:
$facebook->getExtendedAccessToken();
If not, is this what I should be doing?
$accessToken = $facebook->getAccessToken();
$extendedAccessToken = file_get_contents("https://graph.facebook.com/oauth/access_token?
client_id={$appId}&
client_secret={$secret}&
grant_type=fb_exchange_token&
fb_exchange_token={$accessToken}"
);
I've tried it and it doesn't work. I get this error:
Warning: file_get_contents(https://graph.facebook.com/oauth/access_token? client_id=#######& client_secret=#########& grant_type=fb_exchange_token& fb_exchange_token=##########) [function.file-get-contents]: failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request in /...
Does it work any differently if I switch to FQL instead of the graph api? I've read through the Facebook documentation many times, but the PHP sdk is not thoroughly documented and I can't find any examples of how this should work.
I finally figured this out on my own. The answer is pretty anti-climactic. It appears that newly created apps get 60 day access tokens automatically. I'm not sure if this is dependent on enabling the "depricate offline_access" setting in the Migrations section of the app settings. Leave it on to be safe.
So at the time of writing this, you can use the PHP SDK as follows: $facebook->getAccessToken();
(The reason my app wasn't working as expected was unrelated to the expiration of the access token.)
Just one more thing, to get long-lived access token using PHP SDK you should call $facebook->setExtendedAccessToken(); before $facebook->getAccessToken();
In the last Facebook PHP SDK 3.2.0 you have a new function setExtendedAccessToken()
that you have to call before getAccessToken();
Like this:
$user = $facebook->getUser();
$facebook->setExtendedAccessToken(); //long-live access_token 60 days
$access_token = $facebook->getAccessToken();
Actually newly created apps only get a 60 day access token automatically if you are using a server side call. If you are using the client-side endpoint as shown above in the question, even new apps will still receive a short-term token initially. see: https://developers.facebook.com/docs/roadmap/completed-changes/offline-access-removal/
I had the same HTTP/1.1 400 Bad Request error that you had when using the New Endpoint and the problem was if you copy the code Facebook gives you exactly and paste it into your app, there are actually spaces in between the params, meaning there's unnecessary spaces in the url and it won't get called correctly when passed into file_get_contents() even though it works okay when pasted in the browser. This took me way too long to figure out. Hope this helps somebody! Here is my complete working code to get the extended access token out of the new endpoint (replace x's with your values):
$extend_url = "https://graph.facebook.com/oauth/access_token?client_id=xxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxxxxxxx&grant_type=fb_exchange_token&fb_exchange_token=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$resp = file_get_contents($extend_url);
parse_str($resp,$output);
$extended_token = $output['access_token'];
echo $extended_token;
The selected answer is now outdated. Here are Facebook's instructions to swap a short-term token (provided in front-end) for a long-term token (server only):
https://developers.facebook.com/docs/facebook-login/access-tokens/refreshing/
Generate a Long-lived User or Page Access Token
You will need the following:
A valid User or Page Access Token
Your App ID
Your App Secret
Query the GET oath/access_token endpoint.
curl -i -X GET "https://graph.facebook.com/{graph-api-version}/oauth/access_token?
grant_type=fb_exchange_token
client_id={app-id}&
client_secret={app-secret}&
fb_exchange_token={your-access-token}"
Sample Response
{
"access_token":"{long-lived-access-token}",
"token_type": "bearer",
"expires_in": 5183944 //The number of seconds until the token expires
}
From an authenticated referral (such as from a timeline story) to my website, I am trying to use the server-side authentication flow to obtain an access token for the referred user. I need to pass my app secret, the auth code, and the original redirect URI to the Facebook access token endpoint. Since I did not initiate the authentication request, how do I determine the original redirect_uri?
The link from the Facebook timeline looks like:
http://www.facebook.com/connect/uiserver.php?app_id=153644678059870&method=permissions.request&redirect_uri=http%3A%2F%2Fwww.wnmlive.com%2Fpost%2F141833948%3Ffb_action_ids%3D10100708033267487%26fb_action_types%3Dwnm-live%253Acomment%26fb_source%3Drecent_activity&response_type=code&display=page&auth_referral=1
So I figure that the redirect URI I need to pass is:
http%3A%2F%2Fwww.wnmlive.com%2Fpost%2F141833948%3Ffb_action_ids%3D10100708033267487%26fb_action_types%3Dwnm-live%253Acomment%26fb_source%3Drecent_activity
The URI that the user is ultimately redirected to is:
http://www.wnmlive.com/post/141833948?fb_action_ids=10100708032119787&fb_action_types=wnm-live%3Apost&fb_source=recent_activity&code=AQALK-Mwb_Nwi4z7FWnFaL6tEXvNtVJiRKrgarG9X73sp22TJyk8v2GWKtuXuevJk4hPSRNnuNpEgZXLFdOS_k-pY-mE15DYytIa8Y7VdSw3VL-XYi-CR9BCqRQGq4uBJvSSdZayCp6MWzDMaNqWd5r8OhKVnOhg_yDlvfoLl21N2SMwkJaOfD5mlPnPb5A-Q4A#_=_
Is it safe to assume that I can just chop off everything starting with the "&code=" and use that as the redirect URI?
According to a Facebook engineer, the redirect_uri is the current URI up until the "&code=". The code will always be the final query string name/value pair. I have also verified that this works.
Currently (Aug 23 2012) Facebook is adding parameters after the code= , for instance,
http://apps.coincident.tv/newgirltalk/mobile/?ref=bookmarks;code=AQCZmt8n9NyfKNj8Ea9yzeCYCh-m6FcrbFqqnpQRYpfTwsO8DCk5E6CIbYig1I7g5RxDZxNs7pLcQZDdfjdLJy-8IE4BAW56VPNVADTIa9zxsFEVGLTCjfP7tuSNAIeNZdWecI53pQipnt4YpnawoRXDYVVylFZnWoVYdMtVCaOjZ5DUrN9VSByNVkV5ojOoCEY;fb_source=bookmark_favorites;count=0;fb_bmpos=4_0
Deleting everything from code= doesn't yield an access token, nor does carefully deleting just the code=....; section.
This can be recreated by adding a Facebook bookmark pointing to your app, opening www.facebook.com in your mobile device browser, and then going to your app via the bookmark.
In addition to what Carl said,
I narrowed the issue to be because of specific ref parameter.
If you have referral oauth enabled, I'll be unabled to exchange the code for an access_token with specific ref.
Examples:
http://m.facebook.com/apps/App_name/?ref=bookmarks
http://m.facebook.com/apps/app_name/?ref=m_notif
Those will not work with referral oauth no matter what redirect_uri you use for generating the access_token. There are probably other ref parameters that doesn't work.
It's very annoying because we can't have mobile web app working with this issue
As Carl pointed out, there are additional parameters after code. Unlike Carl, if I strip those off and use the resulting url as the redirect uri, it works.
$redirecturi = $_SERVER['SCRIPT_URI'];
$delimiter = "?";
foreach ($_GET as $key=>$val) {
if ($key == "code") break;
$redirecturi .= $delimiter.$key."=".rawurlencode($val);
$delimiter = "&";
}
// now I can use $redirecturi to exchange the code for a token
http://developsocialapps.com/authenticated-referrals-facebook-apps/
I filed a bug on Facebook here : https://developers.facebook.com/bugs/141862359298314
If this still affects your app, please go subscribe.
I see this has been asked a lot here but I still have yet to come up with a solution. I need to get the user's ID to determine if they have already filled out a form in my app. Here is my code..
require_once('facebook.php');
$facebook = new Facebook(array(
'appId' => 'xxxxxxxxxx',
'secret' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'cookie' => false,
));
$signed_request = $facebook->getSignedRequest();
$page_id = "fb" . $signed_request['page']['id'];
$user_id = $facebook->getUser();
I don't know if this is related or not but I can grab the page id just fine. But $user_id keeps returning as 0 for all users except me. I'm guessing that's because I'm an admin of my page.
Does anybody know what the problem is here?
My guess is that most of the reported problems with $facebook->getUser() are related to CSRF (Cross Site Request Forgery) protection that is built into Facebook's PHP SDK and is implemented somewhat awkwardly.
What CSRF protection does is to make sure that a request to get user's data needs to originate from the same server. It does it by storing a random hash in the session. If you call to getUser() without this value set, getUser() will always return 0.
So the user needs to visit your site first, a CSRF token will be generated and stored in the session and only on the following requests you can successfully call getUser()
If you look at the PHP SDK source code you'll notice that the way to generate this CSRF token is to call a protected method called establishCSRFTokenState(). You can't call this method from outside and the only way it gets called is when calling $facebook->getLoginUrl(...)
So, either modify the SDK source to change this behavior (or to make establishCSRFTokenState() public) or just call getLoginUrl(...) when the user first visits your site. Make sure that you have session support enabled.
I think this isn't designed very well and documented even worse. And it doesn't help to protect the site against CSRF attacks in most cases unless people understand how to properly use it.
i has this problem too, the only solution was to use oauth before with permission request
"user_about_me". Since FB uses oauth 2.0, most user values are hidden and you have to request
all this sh*t :(