I am trying to execute the appengineexample of https://github.com/pythonforfacebook/facebook-sdk/. However, my cookie value is always None. I did debug and find that it does carry information however in facebook.get_user_from_cookie, it cannot extract/parse the value.
Has anyone been able to execute this example? I am using Python25. I am trying to implement a similar funcitonality in my example.
I need to log in users via facebook and store their details in app engine datastore.
There could be several reasons produce this issue.
We could not help if there is no details information.
Try to log some information will help us to firgure out what the bug is.
https://github.com/pythonforfacebook/facebook-sdk/blob/master/facebook.py
Since you received None with get_user_from_cookie function.
open the facebook.py, add two log at the line that will produce the None results. Then the log can tell where the issue is.
def get_user_from_cookie(cookies, app_id, app_secret):
"""Parses the cookie set by the official Facebook JavaScript SDK.
cookies should be a dictionary-like object mapping cookie names to
cookie values.
If the user is logged in via Facebook, we return a dictionary with
the keys "uid" and "access_token". The former is the user's
Facebook ID, and the latter can be used to make authenticated
requests to the Graph API. If the user is not logged in, we
return None.
Download the official Facebook JavaScript SDK at
http://github.com/facebook/connect-js/. Read more about Facebook
authentication at http://developers.facebook.com/docs/authentication/.
"""
cookie = cookies.get("fbsr_" + app_id, "")
if not cookie:
logging.info("no cookies") # ADD LOG HERE!
return None
parsed_request = parse_signed_request(cookie, app_secret)
try:
result = get_access_token_from_code(parsed_request["code"], "",
app_id, app_secret)
except GraphAPIError:
logging.info("get access token failed") # ADD LOG HERE!!
return None
result["uid"] = parsed_request["user_id"]
return result
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.".
So I am building a restaurant app and one of the features I want is to allow a user of the app to see photos from a particular restaurant's Instagram account.
And I want a user to be able to see this without having to login to their Instagram account, so they shouldn't even need an Instagram account for this to work.
So I have read this answer How can I get a user's media from Instagram without authenticating as a user?
And I tried what it said and used the client_id(which I recieved when I registered my app using my personal Instagram account), but I still get an error back saying :
{
meta: {
error_type: "OAuthAccessTokenException",
code: 400,
error_message: "The access_token provided is invalid."
}
}
The endpoint I am trying to hit is :
https://api.instagram.com/v1/users/search?q=[USERNAME]&client_id=[CLIENT ID]
So do I absolutely need an access token for this to work(and thus have to enforce a user to log in) ?
If I do, then is there way to generate an access token somehow without forcing the user log in?
I believe there is a way around this, as the popular dating app Tinder has this desired functionality I am looking for, as it allows you to see photos from people's Instagram account without having to log in! (I have just verified this 5 minutes ago!)
Any help on this would be much appreciated.
Thanks.
Edit April 2018: After facebook privacy case this endpoint is immediately put out of service. It seems we need to parse the JSON embedded in <script> tag directly within the profile page:
<script type="text/javascript">window._sharedData = {"activity_counts":...
Any better ideas are welcome.
You can use the most recent link
GET https://www.instagram.com/{username}/?__a=1
to get latest 20 posts in JSON format. Hope you put this to good use.
edit: other ways aren't valid anymore:
https://www.instagram.com/{username}/media/
Instagram used to allow most API requests with just client_id and without access_token, the apps registered back in the day still work with way, thats how some apps are able to show instagram photos without user login.
Instagram has changes the API specification, so new apps will have to get access_token, older apps will have to change before June 2016.
One way you can work around this is by using access_token generated by your account to access photos. Login locally and get access_token, use this for all API calls, it should not change, unless u change password,if it expires, regenerate and update in your server.
Since the endpoints don't exist anymore I switched to a PHP library -
https://github.com/pgrimaud/instagram-user-feed
Installed this lib with composer:
composer require pgrimaud/instagram-user-feed "^4.0"
To get a feed object -
$cache = new Instagram\Storage\CacheManager();
$api = new Instagram\Api($cache);
$api->setUserName('myvetbox');
$feed = $api->getFeed();
Example of how to use that object -
foreach ($feed->medias as $key => $value) {
echo '<li><img src="'.$value->thumbnailSrc.'"></li>';
}
I have a website (Symfony2) with HWIOauthBundle used to connect with Facebook and everything works fine.
Now, I'm trying to build an iOS app with Cordova and Ionic framework (AngularJS) and I want to authenticate my user with Facebook :
With $cordovaFacebook, I authenticate my user and get a valid Facebook access token, that's ok
I try to use this access token to authenticate my user on the server-side with HWIOauthBundle :
GET http://..../login/facebook?code=MY_FACEBOOK_ACCESS_TOKEN
Symfony rejects my request with this log :
INFO - Matched route "facebook_login" (parameters: "_route": "facebook_login")
INFO - Authentication request failed: OAuth error: "Invalid verification code format."
So my question is : how can I authenticate my user on both front and back end with Facebook connect?
Thanks :)
I've also been wondering how to implement a server side login with the HWIOAuthBundle.
I didn't find any solution on the web, so I coded the functionnality based on hints I've read on the net.
Basically, you have to :
authenticate the user on your app
make an http request to your server with the Facebook token.
ont the server side, check if the token is for your Facebook app, and retrieve the user's Facebook ID.
Get your user from the DB based on the fetched ID.
Here's my Symfony controller:
public function getSecurityFbAction($token)
{
// Get the token's FB app info.
#$tokenAppResp = file_get_contents('https://graph.facebook.com/app/?access_token='.$token);
if (!$tokenAppResp) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Make sure it's the correct app.
$tokenApp = json_decode($tokenAppResp, true);
if (!$tokenApp || !isset($tokenApp['id']) || $tokenApp['id'] != $this->container->getParameter('oauth.facebook.id')) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Get the token's FB user info.
#$tokenUserResp = file_get_contents('https://graph.facebook.com/me/?access_token='.$token);
if (!$tokenUserResp) {
throw new AccessDeniedHttpException('Bad credentials.');
}
// Try to fetch user by it's token ID, create it otherwise.
$tokenUser = json_decode($tokenUserResp, true);
if (!$tokenUser || !isset($tokenUser['id'])) {
throw new AccessDeniedHttpException('Bad credentials.');
}
$userManager = $this->get('fos_user.user_manager');
$user = $userManager->findUserBy(array('facebookId' => $tokenUser['id']));
if (!$user) {
// Create user and store its facebookID.
}
// Return the user's JSON web token for future app<->server communications.
}
I throw the Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException exceptions to handle login errors on my app.
Of course, you really should use https because you will be exchanging sensible information.
I don't know if it's the best way to do it but it works well.
Hope it helps !
Well, I think that Symfony doesn't actually reject your request. Facebook is. I'm not sure if this might help, but I know that a bunch a problems can happen when dealing with the Facebook Auth :
Do you know if the tool sends, along with the code parameter, a redirect_uri parameter ? If so :
Did you check that your redirect_uri HAS a trailing slash at the end ? See this
Silly question, but did you check that your app_id is the same when you got authorized via Cordova ?
Check that your redirect_uri DOES NOT have any query parameter.
Check that the redirect_uri that you use during the whole process is the same all the time.
Overall, it seems that your issue is almost all the time related to the redirect_uri URI format.
If I programmatically create a Facebook test user, the login_url for the new user doesn't work. Fetching the login_url returns a 404 error.
Pared-down example (in Python). The last two lines are where the problem shows up:
import requests
from urlparse import parse_qs
APP_ID = "<Facebook App ID>"
APP_SECRET = "<Facebook Client Secret>"
# Get app access token - this works
response = requests.get('https://graph.facebook.com/oauth/access_token',
params={'grant_type': "client_credentials",
'client_id': APP_ID, 'client_secret': APP_SECRET})
app_access_token = parse_qs(response.content)['access_token'][0]
# Create test user - this works
response = requests.post('https://graph.facebook.com/%s/accounts/test-users' % APP_ID,
data={'access_token': app_access_token, 'installed': "true"})
test_user = response.json()
login_url = test_user['login_url']
print login_url # http://developers.facebook.com/checkpoint/test-user-login/...
# Get cookied for login - see https://stackoverflow.com/a/5370869/647002
session = requests.Session()
session.get("https://www.facebook.com/", allow_redirects=True)
# Login test user - THIS FAILS
response = session.get(login_url)
print response.status_code # 404
Others have noted that you must first fetch the Facebook homepage before test user's login_url will work. We ran into that same problem, and I've included that workaround above without any luck. [Edit: added the _fb_noscript=1 query param, required starting mid-2015 for non-JavaScript test clients.] [Edit 8/2017: now removed _fb_noscript=1; no longer required, and sets a noscript cookie that makes some later FB auth requests return 500.]
I also tried opening the login_url directly in a browser:
If I'm not already logged into Facebook, I get a generic Facebook 404 page.
If I'm already logged into my developer account, Facebook warns that I'll be logged in as a platform test user, and then allows me into the test user's account.
That last point seems to confirm that the test user is being created properly and that I have the correct login_url. But of course, that's no help for automated testing. (We don't want to run tests logged into my developer account.)
Is there some other way the test user's login_url is meant to be used for automated testing?
A Facebook developer support engineer has confirmed that the test-user login_url can no longer be used for automated login of a test user, due to security changes. Apparently it's meant for manual testing.
I am, however, able to achieve automated login of a programmatically-created Facebook test user by posting to Facebook's normal login form. It seems like all you need are the email and password returned from the create-test-user API. (No other login form fields seem to be needed, though you'll still need to pick up the cookies first.)
The code below is working for me now (replacing the last two "this fails" lines of code from the original question):
# Login test user - THIS WORKS
response = session.post("https://www.facebook.com/login.php",
data={'email': test_user["email"],
'pass': test_user["password"]})
print response.status_code # 200
I haven't found this documented anywhere, and Facebook may change their login form in the future, so YMMV.
I have a Facebook app that works fine when I call $facebook->api('/me'), it returns all the user information, but it fails when I call $facebook->api('/100006737731259'). The error I get is:
array("error" => array("message" => "Unsupported get request.", "type" => "GraphMethodException", "code" => 100))
And the strange thing is that if I open my browser and go to http://graph.facebook.com/100006737731259 it returns all the information with no problem (it is one test user for my app).
Have you ever had a problem like it? I do not know what can I be doing wrong.
Thank you very much
When call this API for test user, you can put empty access token OR just don't put access_token parameter at all, then you can solve it.
If you really want to put the access_token, there's the rule you have to follow:
Prohibited access_token:
Normal user's access token
Other app's test user access token
Other app access token
Allowed access_token:
Test user's access token(Either the test user is current app's other test user or this test user 100006737731259, both is allowed!) retrieved from https://graph.facebook.com/APP_ID/accounts/test-users?installed=true&name=TEST_USER_NAME&locale=en_US&permissions=read_stream&method=post&access_token=APP_ACCESS_TOKEN (Replace the relevant APP_ID, TEST_USER_NAME, and APP_ACCESS_TOKEN)
Current App Access token
*APP_ACCESS_TOKEN can be retrieved from https://graph.facebook.com/oauth/access_token?client_id=APP_ID&client_secret=APP_SECRET&grant_type=client_credentials (Replace the relevant APP_SECRET)
**App Secret can be get from https://developers.facebook.com/x/apps/APP_ID/settings/ (Replace relevant APP_ID)
The proof is, if you request with other user access token, https://graph.facebook.com/100006737731259?access_token=PROHIBITED_ACCESS_TOKEN at web browser, you would get error eventually.
But if you do https://graph.facebook.com/100006737731259?access_token=Allowed_ACCESS_TOKEN OR https://graph.facebook.com/100006737731259?access_token= (left the access_token value empty) with your web browser, then you can get the data.
This is a problem that only occurs with test users. I don't know why, but it is. If you use a real user, this will not happen.