Facebook Graph API get First and Last name from PSID? - facebook

I have setup a FB Webhook to notify my technicians when a user messages my business page. The notification works and I get the message and the sender's ID (PSID) but I can't seem to get the sender's first and last name per the documentation found here :
https://developers.facebook.com/docs/messenger-platform/identity/user-profile
I have been granted Advanced Access with the "Business Asset User Profile Access" as required.
The App is in Live mode (not development mode)
Messaging permissions are granted
I need to turn the returned "Sender ID (PSID)" into a First and Last name. According to the documentation, I need to send a request like this :
curl -X GET "https://graph.facebook.com/<PSID>?fields=first_name,last_name,profile_pic&access_token=<PAGE_ACCESS_TOKEN>"
So my code looks like this :
function get_basic_info($id, $access) {
$url = 'https://graph.facebook.com/'.$id.'?fields=first_name,last_name,profile_pic&access_token='.$access;
$info = json_decode(file_get_contents($url), true);
return $info;
}
I would then call the function using : $fbuser = get_basic_info($sender, $fb_access_token);
This will ALWAYS return NULL when messaging my business page from any Facebook account.... except from my personal account which owns the business page. If I message my business account from my personal account that owns the business, this is what I get back :
{"first_name":"Tim","last_name":"My_Last_Name","profile_pic":"Profile_Picture_URL","id":"My_FB_ID"}
The access token I am using is generated from the App Dashboard > My_App > Messenger (under Products, left side) > Settings > Access Tokens > Generate Token (Next to the Business Page I own).
What am I doing wrong? It works when I personally message my own business page, but not when anyone else messages. Thank you for ANY help!

So to update this with an answer for those who may be looking, here it goes.... Don't use the Sender ID (PSID) as the documentation states, use the Message ID.
function get_basic_info($id, $access) {
$url = 'https://graph.facebook.com/'.$id.'?fields=from&access_token='.$access;
$info = json_decode(file_get_contents($url), true);
return $info;
}
Usage :
$fbuser = get_basic_info($message_id, $FB_PAGE_ACCESS_TOKEN);
$fb_name = $fbuser['from']['name'];
Unfortunately, you cannot get the Profile Picture, but this is as far as I needed to get anyways.
Enjoy!

Related

Identifying Facebook Messenger user with UserID from a Facebook Login

I am trying out the new Facebook Messenger Platform and have hit a bit of a problem.
When a user first chats with my Bot, I want to use the sender.id to lookup the user in my DB and verify whether they're a customer or not and offer a more tailored UX.
User's sign up to my service using Facebook Login, but unfortunately it appears my App's Facebook ID & my Bot's Facebook ID are different due to IDs being limited to App-scopes.
Is there any way associate the 2 IDs to allow me to find a user in my DB?
UPDATE (4/20/2016):
We got around this by asking users on first contact via messenger to click a link to login to their account so we could associate their messenger_id with their account in our DB.
Would be awesome if facebook instead included PAGE_SCOPED IDs in the ids_for_business endpoint.
UPDATE: (6/1/2016):
Facebook's latest update includes a new "Account Linking" functionality that appears to solve this issue. See https://developers.facebook.com/docs/messenger-platform/account-linking
Facebook's latest update includes a new "Account Linking" functionality that appears to solve this issue. See https://developers.facebook.com/docs/messenger-platform/account-linking
Unfortunately, there's no way of doing that currently. Asking them to login for new threads is the best way of linking accounts.
Yes. You can get details like first name, last name, profile pic url, locale, timezone, gender from an api. Only you have to pass is their recipient id/sender id and acccess_token of your messenger bot.
https://graph.facebook.com/v2.6/USER_ID?fields=first_name,last_name,profile_pic,locale,timezone,gender&access_token=TOKEN
I solved it different way but it works perfectly by graph API,i read mailbox of my page so that when any one can interact by messenger bot than i read pages inbox and iterate through,
Step 1:
Do a HTTP get request by graph API ,
you want a PAGE_UNIQUE_ID from Graph API ,
GET REQUEST
https://graph.facebook.com/v2.6/<PAGE_UNIQUE_ID>?fields=conversations.limit(10){participants,updated_time,id}&access_token=<PAGE_ACCESS_TOKEN>
PAGE_UNIQUE_ID Hints:
Go ===> https://developers.facebook.com/tools/explorer/ ==> Press "Get Token" ===> Select your desired page ===>Finally Submit , You show a id on output that is PAGE_UNIQUE_ID in here.
Check on browser for resoponse.
Step 2:
After doing above http request ,you get a JSON object that will show latest 10 conversation of pages where desired facebook id included.
Step 3:
Do iteration through by user full name or you can use lodash or underscore at your choice,
getUserID(response,'Zahid Rahman')
function getUserID(response, fullname) {
if (response && response.conversations && response.conversations.data) { //Check response is correct
var conversations = response.conversations.data; //Get all conversations
for (var j = 0; j < conversations.length; j++) {
var conversationsParticipants = conversations[j].participants.data;
for (var k = 0; k < conversationsParticipants.length; k++) { //Get all particiapnts of a single conversation.
var conversationsParticipantsEach = conversationsParticipants[k];
if (conversationsParticipantsEach.name === fullname) { //Check fullname match or not
console.log("Desired Facebook User ID : " + conversationsParticipants[k].id);
return conversationsParticipants[k].id;
}
}
}
}
}
Hope it will help you.
This is probably what you want: https://developers.facebook.com/docs/apps/for-business
It allows you to get all of the app-scoped user ids on a per-business basis.

Generate access token Instagram API, without having to log in?

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>';
}

Google Sign-In with Passportjs not getting authenticated

I'm using Sails with Passport for authentication. I'm using passport-google-oauth(OAuth2Strategy) and passport-facebook for enabling Google Sign-in.
I'm not too well-versed with Passport, so pardon me if this is a rookie question. I've set up login via Facebook and it works just fine. With Google, I do receive an authorization code after allowing access to the app, but the I'm eventually not authenticated. I'm guessing the same code should work for both Facebook and Google since the strategies are both based on oauth2.
I'm not even sure what code to share, since I'm using the auto-generated code from sails-generate-auth, but do let me know if there's anything else I can share.
Any ideas on why this might be happening? The app is locally hosted but that's unlikely to be the problem since I am getting to the authorization stage anyway.
I faced the same problem and it was located here in in api/services/passport.js:
// If the profile object contains a list of emails, grab the first one and
// add it to the user.
if (profile.hasOwnProperty('emails')) {
user.email = profile.emails[0].value;
}
// If the profile object contains a username, add it to the user.
if (profile.hasOwnProperty('username')) {
user.username = profile.username;
}
// If neither an email or a username was available in the profile, we don't
// have a way of identifying the user in the future. Throw an error and let
// whoever's next in the line take care of it.
if (!user.username && !user.email) {
return next(new Error('Neither a username nor email was available'));
}
The Google service was not returning a profile.username property.
Because of it, the user is not saved in the database and cannot be authenticated. Then the passport callback receives an empty user, so the function that handles errors is fired and the user is redirected to the login page.
This change allows to use the displayName property as the username:
// If the profile object contains a list of emails, grab the first one and
// add it to the user.
if (profile.hasOwnProperty('emails')) {
user.email = profile.emails[0].value;
}
// If the profile object contains a username, add it to the user.
if (profile.hasOwnProperty('username')) {
user.username = profile.username;
}
/** Content not generated BEGIN */
// If the username property was empty and the profile object
// contains a property "displayName", add it to the user.
if (!user.username && profile.hasOwnProperty('displayName')) {
console.log(profile); // <= Use it to check the content given by Google about the user
user.username = profile.displayName;
}
/** Content not generated END */
// If neither an email or a username was available in the profile, we don't
// have a way of identifying the user in the future. Throw an error and let
// whoever's next in the line take care of it.
if (!user.username && !user.email) {
return next(new Error('Neither a username nor email was available'));
}
You could also use the profile.id property because profile.displayName is not necessarily unique (ie: two Google accounts can have an identical displayName). But it is also true accross different services: a Twitter account could also have the same username than a Facebook account. If both register on your application, you will have a bug. This is a problem from the code generated by sails-generate-auth and you should adapt it with the behavior that you want.
I will propose a PR if this solution works for you too.
Alright, so this ultimately turned out to be a known issue with the API.
TL;DR: Enable the Google+ API and the Contacts API as mentioned here. (The Contacts API isn't required, as #AlexisN-o pointed out in the comments. My setup worked as desired with Contacts API disabled. This obviously depends on what scope you're using.)
I believe it's not a nice way of failing since this was an API error that was prevented from bubbling up. Anyway, I dug into passport.authenticate to figure out what was going wrong. This eventually calls the authenticate method defined in the package corresponding to the strategy (oauth2 in this case). In here (passport-google-oauth/lib/passport-google-oauth/oauth2.js) I found that the accessToken was indeed being fetched from Google, so things should be working. This indicated that there was a problem with the requests being made to the token urls. So I ventured a little further into passport-oauth2/lib/strategy.js and finally managed to log this error:
{ [InternalOAuthError: failed to fetch user profile]
name: 'InternalOAuthError',
message: 'failed to fetch user profile',
oauthError:
{ statusCode: 403,
data: '{
"error": {
"errors": [{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured. The API (Google+ API) is not enabled for your project. Please use the Google Developers Console to update your configuration.",
"extendedHelp": "https://console.developers.google.com"
}],
"code": 403,
"message": "Access Not Configured. The API (Google+ API) is not enabled for your project. Please use the Google Developers Console to update your configuration."
}
}'
} }
This was the end of the hunt for me and the first result for the error search led to the correct answer. Weird fix though.

testing facebook real time updates / user comments

I'm trying to integrate realtime updates for user pages. I have a callback running on a given HOST url. Having this the subscription creation is:
G = facebook.GraphAPI()
app_token = config['FACEBOOK_APP_ID'] + '|' + config['FACEBOOK_SECRET']
path = config['FACEBOOK_APP_ID'] + '/subscriptions'
post_args = {'access_token' : app_token, 'callback_url' : HOST, 'fields' : 'feed', 'object' : 'page', 'verify_token' : 'token'}
G.request(path, post_args=post_args)
This seems to work just fine and a subscription is created. After this, for a given user I get oauth credentials with perms = ["publish_stream", "offline_access", "manage_pages", "publish_actions", "read_stream"]
Using this access token, I do a subscribe by adding the app to the page tabs:
G = facebook.GraphAPI(access_token)
path = "/%s/tabs" % page['id']
G.request(path, post_args={'app_id' : config['FACEBOOK_APP_ID']}
Now things work.... sort of. First thing is I'm not sure exactly how facebook testing should work in practice. Basically I created a bunch of test users using the app settings on developers page. Then using one of these users, I create two separate pages Page1, Page2 and I registered the app as a tab on these pages. Posts issued from the test users, or from the real user I created the app with are picked up. But I try to find one of the pages from some other real user (so not a test one and not the one I created the app with) and I cant. Even if I copy paste the entire URL, I just get a redirect to the first page. Are those pages only visible inside my own test app/users context ? Should I create a page from my real account and test with that? I'm just curious on how would I go around testing this in a real setup. Would I get ALL comments / posts on that page regardless of the user who does the posting or just posts from the Page / Admins of the page ?
Another separate problem I'm having is creating a comment from some user. So I'm using the exact same access token I've got above, and having a post from someone come it, I want to issue a reply in the form of a comment on that post. I have the facebook post id, so I just:
graph = facebook.GraphAPI(access_token)
graph.put_comment(facebook_post_id, message)
Say I issue this command using the access token I got from TestUser1 on a post that came on his own page Page1 . I would expect that the comment be posted on behalf of TestUser1 but instead it gets posted on behalf of Page1 . Is this expected as a side effect of the token I'm using? I've read here https://developers.facebook.com/docs/facebook-login/access-tokens/ that there are user access tokens and page access tokens; but I've tried the exact same thing with a token without the 'manage_pages' perms and still get the same thing.
Cheers, Bogdan

How to subscribe to real-time updates for a Facebook page's wall

Facebook's real-time updates docs now say that you can get the feed for a page:
You can subscribe to the page's feed in the same way you subscribe to
a user's feed - the subscription topic should be 'user' and the
subscription field should be 'feed'
My understanding of this is that I need to post to the graph API to subscribe as such:
curl -d \
"object=user&fields=feed&callback_url=$CALLBACKURL&verify_token=$SECRET" \
"https://graph.facebook.com/$PAGEID/subscriptions?access_token=$OAUTHTOKEN"
(This is a bash script.) Here $CALLBACKURL is set up correctly following their example code. (At least I think it's correct -- I can successfully add subscriptions with it.)
The $OAUTHTOKEN is the one for my Facebook App.
And the $PAGEID is the facebook object id of the page I'd like to get realtime updates for.
When I do this, the call appears to work -- no error message. My callback gets called. But I certainly don't get notified when something happens on the page's feed.
So what's missing? Does the page need to install the app whose oauth token I'm using? Or do I somehow need to get an oauth token for the page itself by logging in as the page?
I do not know if this can help you but I'll tell you where I am for real-time update page feed:
(permissions : manage_page,offline_access,read_stream)
your application must be linked to the page (then install the application but not required to have a tab ex. create tab https://graph.facebook.com/PAGE_ID/tabs?app_id=APP_ID&method=POST&access_token=PAGE_ACCESS_TOKEN and delete tab
TAB_ID=PAGE_ID.'/tabs/app_'.APP_ID;
https://graph.facebook.com/TAB_ID?method=DELETE&access_token=PAGE_ACCESS_TOKEN)
function page_access_token($page_id,$access_token){
$page_token_url="https://graph.facebook.com/" .
$page_id . "?fields=access_token&" . $access_token;
$response = file_get_contents($page_token_url);
$resp_obj = json_decode($response,true);
$page_access_token = $resp_obj['access_token'];
return $page_access_token;
}
function page_tabs_create($page_id,$app_id,$page_access_token){
$page_settings_url = "https://graph.facebook.com/" .
$page_id . "/tabs?app_id=".$app_id."&method=POST&access_token=" . $page_access_token;
$response = file_get_contents($page_settings_url);
$resp_obj = json_decode($response,true);
return $resp_obj;
}
function page_tabs_delete($tab_id,$page_access_token){
$page_settings_url = "https://graph.facebook.com/".$tab_id."?method=DELETE&access_token=" . $page_access_token;
$response = file_get_contents($page_settings_url);
$resp_obj = json_decode($response,true);
return $resp_obj;
}
Subscription: to subscribe must be like a "user" and therefore object = user fields = feed but you have to add new fields because otherwise it receives the comments and likes the wall so you must add "status" in order to receive the articles posted (my problem is to get other content such as links I have managed to add "link" as fields but I am not receiving notifications when a link is posted)
$param = array ('access_token' => $ access_token,
'object' => 'user',
'fields' => 'feed, status, link'
'callback_url' => 'http:// ******** fbcallback.php'
'verify_token' =>'***********',
'include_values' => 'true');
POST
https://graph.facebook.com/APP_ID/subscriptions
my English is not very good but I hope it will help you, on my side I'm still looking for really all updates to the wall (links, video ...)
I have been researching on this and i am getting the pushes for pages too.
while subscribing make sure that object = user and fields = feed, status is present.
Make sure that application is added to your page, then only you will receive the update.
Response received from facebook is as below :-
{"entry":[{"id":"*******","uid":"*****","time":1332940650,"changed_fields":["status"]}],"object":"user"}
where **** is my pageId.
The above push is received on adding a new post , as you can see the changed_feild is status , but when we post on wall the changed_fields comes as feed. Below link helped me in receiving pushes for the page.
http://bugs.developers.facebook.net/show_bug.cgi?id=18048
Firstly, subscription to real-time update for page/feed doesn't work.
See: http://bugs.developers.facebook.net/show_bug.cgi?id=18048
Does the page need to install the app whose oauth token I'm using?
Yes
Or do I somehow need to get an oauth token for the page itself by logging in as the page?
If i correctly understand you, you need only app access_token
https://graph.facebook.com/oauth/access_token?client_id=your_app_id&client_secret=your_secret&grant_type=client_credentials
I first started reading the docs about real-time updates thinking that it could delivery the actual data. But, as I realized, that's not the purpose.
Real-time updates are just to tell you that something has changed, and once it happens, you can call the api with the conventional method.
Also, seems like there's an error on this part the subscription topic should be 'user' and the subscription field should be 'feed'. The subscription topic, actually, should be 'page'. (Have you thought the same?)
And by subscribe on page feed as the same as user feed, means that you can get update notifications, not the data itself.
Not sure if this is a common mistake, but I'm posting it just in case.
--
Currently I'm working on a data mining tool that will need real-time updates. But first, I'm focused on the data itself, so I can't post any examples yet. (I'll edit this answer when implementing this part)
What I can say about your issue is:
1) Look that your $PAGEID isn't correct. Actually it's your APPID instead.
2) After subscribing, have your subscription appeared on the list when calling https://graph.facebook.com/<app-id>/subscriptions?access_token=... ?
3) With user subscription, does it work? Or is it just with pages?
For this you need to set up an endpoint URL that receives both HTTP GET (for subscription verification) and POST (for actual change data) requests from Facebook.
Then you should make a POST to the graph API url https://graph.facebook.com/<app-id>/subscriptions?access_token=<access_token> to subscribe, and be ready to handle the verification request.
Then to list subscriptions, just perform a GET request on the same url, https://graph.facebook.com/<app-id>/subscriptions?access_token=<access_token>, which returns a JSON-encoded content that lists your subscriptions, up to one per object type.
Before you start waiting for the notifications you should check if the URL is actually being hit or not by FB
Check The Output of Following:
"https://graph.facebook.com/".FACEBOOK_APP_ID."/subscriptions?".$appToken."&client_secret=".FACEBOOK_SECRET;
This shall return the callback_url if set correctly !