I want to integrate SalesForce with Facebook Messenger. For this I've retrieved access token, app id , app secret. When I hit a HTTP request in developer console to send a message then there is an error.
In the given code it is not accepting messages as parameter throwing error but working without messages.
ref: https://developers.facebook.com/docs/messenger-platform/send-messages/?translation#sending_text
Httprequest req = new httpRequest();
req.setEndPoint('https://graph.facebook.com/v5.0/1798927698340/messages?access_token={PUT-ACCESS-TOKEN-HERE}');
String body = '{'+
'"recipient": {'+
'"id": "100042977199143"'+
'},'+
'"message": {'+
'"text": "hello, world!"' +
'}' +
'}';
req.setMethod('POST');
req.setHeader('Content-Type','application/json');
Http h = new Http();
HttpResponse res = h.send(req);
system.debug(res.getBody());
error message :
16:55:58:127 USER_DEBUG [16]|DEBUG|{"error":{"message":"Unsupported
post request. Object with ID 'me' does not exist, cannot be loaded due
to missing permissions, or does not support this operation. Please
read the Graph API documentation at
https://developers.facebook.com/docs/graph-api","type":"GraphMethodException","code":100,"error_subcode":33,"fbtrace_id":"AcqDT5M6mGXSOCr4mOd3kDf"}}
actual response : success = true
This problem arises sometimes when we use invalid access token or user access token instead of page access token.
I have an EXTREMELY strange issue with the search.
I am doing a query by using a GET on
https://sonar-sandbox.gredspdev.loc/_api/search/query?querytext='DMSSonarDocId:5042aa1f-b3a4-4577-8e21-8a47ca27c243 OR DMSSonarDocId:1401144b-bd3d-429a-a386-5061ecc714e1'&sourceid='a0f4d450-e701-4f2a-888a-8d871002752d'&trimduplicates=false&rankingmodelid='05289DBE-73E9-4665-BF69-EE68274176EB'&rowlimit=9000&enablestemming=false&enablesorting=false&selectproperties='DMSSonarDocId,<...>'
I am authenticating using a bearer token generated for my user. This query returns 7 items. Then I am executing THE SAME URL in my browser with my user (NTLM) and it returns 10 items. That is not all. I generate the token for my user one more time. Paste it to the previous GET request with a bearer token and it returns 10 items... I am waiting few seconds, lets say 30... GET one more time and I have 7 items returned (always the same)! And this is 100% replicable. After another GET from the browser and regeneration of the token 10 items, after some time on the same token 7 items....
Update. I have found difference in logs in ULS:
When working correct:
Context has no SMTP/UPN claims. IdentityContext: '{"nameid":"s-1-5-21-2843295230-2675739751-2774624307-1482","nii":"urn:office:idp:activedirectory","upn":"kowalj#spdev.loc","userId":"0#.w|spdev\\kowalj","appliesTo":"https:\/\/sonar-sandbox.spdev.loc\/"}'
When not working correct:
Context has no SMTP/UPN claims. IdentityContext: '{"nameid":"s-1-5-21-2843295230-2675739751-2774624307-1482","nii":"urn:office:idp:activedirectory","upn":"spdev\\kowalj","userId":"0#.w|spdev\\kowalj","appliesTo":"https:\/\/sonar-sandbox.spdev.loc\/"}'
ANOTHER FINDINGS:
Missing items are those which are assigned to me directly - not through group resolved by our custom claims provider - yes, we have a custom claims provider which worked ok for a long time (we were using only NTLM authorization).
We are sending those claims:
new Claim[]
{
new Claim("nameid", sid),
new Claim("nii", Constants.Auth.Token.IdentityIssuer)
};
ANOTHER FINDINGS:
When everything work correctly, executing this code in the SP farm solution in some REST proxy: ((ClaimsIdentity)HttpContext.Current.User?.Identity).Claims.FirstOrDefault(c => c.ClaimType.EqualsIgnoreCase(ClaimTypes.Upn)) returns upn.
When the search is not working, the same code returns null... And as I said, I can refresh the page and at the beginning the upn is there and after some time it is not...
I have found a work around. Not very good but I do not see any other option for now.
We have started Claims to Windows Token Service and if user does some requests to our app, we do (from time to time) requests to our custom proxy placed in the SharePoint farm solution to simulate using SharePoint by that user by using normal windows authentication:
public void RefreshUpn()
{
WindowsImpersonationContext _wic = null;
try
{
string login = HttpContext.Current.User.Identity.Name;
login = login.Substring(login.LastIndexOf('|') + 1);
string[] loginParts = login.Split('\\');
string loginForUpnLogon = Culture.Invariant($"{loginParts[1]}#{loginParts[0]}");
WindowsIdentity wi = S4UClient.UpnLogon(loginForUpnLogon);
if(wi == null)
{
throw new InvalidOperationException(Culture.Invariant($"Could not impersonate user '{HttpContext.Current.User.Identity.Name}'."));
}
_wic = wi.Impersonate();
using (var wc = new WebClient())
{
wc.UseDefaultCredentials = true;
var requestUrl = HttpContext.Current.Request.Url;
wc.DownloadString(requestUrl.Scheme + "://" + requestUrl.Host + "/_api/web/currentuser");
}
}
finally
{
_wic?.Undo();
}
}
After such request, SharePoint responses to us correctly for around 150 seconds.
To create a especific test on my application using Postman, after login and get the JWT token, I need to get a especific claim value to use in a variable in another POST on Postman.
Is that possible without develop a API to do it?
Thanks
Here is a simple function to do that.
let jsonData = pm.response.json();
// use whatever key in the response contains the jwt you want to look into. This example is using access_token
let jwtContents = jwt_decode(jsonData.access_token);
// Now you can set a postman variable with the value of a claim in the JWT
pm.variable.set("someClaim", jwtContents.payload.someClaim);
function jwt_decode(jwt) {
var parts = jwt.split('.'); // header, payload, signature
let tokenContents={};
tokenContents.header = JSON.parse(atob(parts[0]));
tokenContents.payload = JSON.parse(atob(parts[1]));
tokenContents.signature = atob(parts[2]);
// this just lets you see the jwt contents in the postman console.
console.log("Token Contents:\n" + JSON.stringify(tokenContents, null, 2));
return tokenContents;
}
The signature bit is still useless in this example, so you can not validate it with this, but it still addresses your question.
var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable("token", jsonData.token);
Follow the:
https://blog.postman.com/extracting-data-from-responses-and-chaining-requests/
I've created a request in Postman that 'logs in' and, then, the tests section of the response contains the following
var data = JSON.parse(responseBody);
postman.clearGlobalVariable("access_token");
postman.setGlobalVariable("access_token", data.access_token);
This puts the access token in a global variable so you can use it anywhere. If you're looking to read something from the JWT's claim, it's a bit more complicated.Check out how to add a library at https://github.com/postmanlabs/postman-app-support/issues/1180#issuecomment-115375864. I'd use the JWT decode library - https://github.com/auth0/jwt-decode .
I'm new to integrating facebook into the websites I'm working on and trying to get a long term access token by following the instructions here: https://developers.facebook.com/docs/facebook-login/access-tokens/
Even when using the Graph API Explorer here: https://developers.facebook.com/tools/explorer/
I enter the following and populate it with my AppID and AppSecret and current token I get when I press Get Access Token...
GET /oauth/access_token?
grant_type=fb_exchange_token&
client_id={app-id}&
client_secret={app-secret}&
fb_exchange_token={short-lived-token}
I get the return
{ "error": "Invalid response" }
Can someone elaborate on what I might be doing wrong, or the steps in greater detail that works for you in acquiring this long term token.
I've tried to follow what's happening in this thread Facebook Page Access Tokens - Do these expire? with no more success. Any help would be greatly appreciated.
Thanks for your time and help.
Cheers,
-Ryan
You can't get the long-lived user token using the Graph API Explorer. You have to make a GET request to:
https://graph.facebook.com/oauth/access_token?
grant_type=fb_exchange_token&
client_id={app-id}& client_secret={app-secret}& fb_exchange_token={short-lived-token}
You can check it in the browser.
If you need the page access token, you can have a never expiring token. Check out the accepted answer here: What are the Steps to getting a Long Lasting Token For Posting To a Facebook Fan Page from a Server
So I thought I'd revisit this and provide the documentation I wrote that will hopefully help someone else get this happening!
ONE. Create Application
Create an application associated with the user of the page you want to have access to.
TWO. Get Required Pieces of Info
After creating an App we should have two key pieces of info:
App ID: AAAAA (should be about ~15 characters long)
App Secret: BBBBB (should be about ~32 characters long)
With these by going to https://developers.facebook.com/tools/explorer
Making sure to select the correct Application from the Dropdown Box at the top.
Click on Get Access Token and get a ‘fresh’ token.
Here you'll need to select appropriate permissions for your specific app's purpose.
CCCCC (should be ~200 characters long)
THREE. Get Long Life Token (2 Month)
You should then have the pieces of info needed to run the query to get a long-term (2 month) token:
https://graph.facebook.com/oauth/access_token?grant_type=fb_exchange_token&client_id={app-id}& client_secret={app-secret}& fb_exchange_token={short-lived-token}
Replace {app-id}, {app-secret} and {short-lived-token} with the three bits of info you’ve taken note of so far.
You should get a request like the following:
https://graph.facebook.com/oauth/access_token?%20grant_type=fb_exchange_token&%20client_id=AAAAA&%20client_secret=BBBBB&%20fb_exchange_token=CCCCC
Place this query into the url bar of an internet browser. You should get a response in the window that looks something like the following:
access_token=DDDDD&expires=5184000
DDDDD (should be ~200 characters long)
FOUR. Test Token (Part 1)
If you enter the highlighted part into the input on the following debug site:
https://developers.facebook.com/tools/debug/
It should give you an expiry of approximately 2 months.
FIVE. Get Non Expiring Page Token
Now taking note of this new long-live-token we’ll use this to get a token that doesn’t expire, unless the associated application is removed from a user’s access or deleted.
We use either the page name or preferably page-id when making the request:
You can get your facebook page id using something like http://findmyfacebookid.com/
We'll refer to your page id as EEEEE
https://graph.facebook.com/{page-id}/?fields=access_token&access_token={long-live-token}
You should get a request like the following:
https://graph.facebook.com/EEEEE/?fields=access_token&access_token=DDDDD
This will return something like the following:
{
"access_token": "FFFFF",
"id": "131062838468"
}
FFFFF (should be ~200 characters long)
SIX. Test Token (Part 2)
Take the highlighted part and enter it into the debug page and you should get something that shows the token never expires and you’ve been successful in acquiring your never expiring page token.
SEVEN. High Five!
Sorry for the long list of how to achieve this, but I find it better to give the whole process instead of just a small snippet. Let me know if you find this helpful or you have a better way of achieving any of the steps.
Facebook PHP SDK has already implemented method to get long-lived token using short-lived token, after login successfully and got the short-lived token, simple calling
$result = $facebook->setExtendedAccessToken();
if $result is null, it means you got the long-lived access token.
client side
if (response.status === 'connected') {
{
event.preventDefault();
FB.login(function (response) {
if (response.authResponse) {
var profileId = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
var e = response.authResponse.accessToken;
document.getElementById('token').innerHTML = e;
var profileName = "";
var pagesList = "";
var isPage = 0;
var type = "fb";
$.ajax({
url: "WebService1.asmx/getlonToken",
type: "POST",
dataType: 'json',
data: '{accessToken:"' + accessToken + '"}',
contentType: "application/json; charset=utf-8",
async: true,
success: function (response) {
accessToken = response.d;
document.getElementById('status').innerHTML = accessToken;
},
error: function (e) {
alert('Error' + e);
}
});
}
}, { scope: 'user_about_me,friends_about_me,user_activities,friends_activities,user_birthday,friends_birthday,user_education_history,friends_education_history,user_events,friends_events,user_groups,friends_groups,user_hometown,friends_hometown,user_interests,friends_interests,user_likes,friends_likes,user_location,friends_location,user_notes,friends_notes,user_photos,friends_photos,user_relationships,friends_relationships,user_relationship_details,friends_relationship_details,user_status,friends_status,user_videos,friends_videos,user_website,friends_website,email,manage_pages,publish_stream,read_stream,read_page_mailboxes,read_insights, read_mailbox' });
}
Server side
[WebMethod]
public string getlonToken(string accessToken)
{
var fb = new FacebookClient(accessToken);
dynamic result = fb.Get("oauth/access_token", new
{
client_id = 123,
client_secret = "123fff45",
grant_type = "fb_exchange_token",
fb_exchange_token = accessToken,
scope = "user_about_me,friends_about_me,user_activities,friends_activities,user_birthday,friends_birthday,user_checkins,friends_checkins,user_education_history,friends_education_history,user_events,friends_events,user_groups,friends_groups,user_hometown,friends_hometown,user_interests,friends_interests,user_likes,friends_likes,user_location,friends_location,user_notes,friends_notes,user_photos,friends_photos,user_relationships,friends_relationships,user_relationship_details,friends_relationship_details,user_religion_politics,friends_religion_politics,user_status,friends_status,user_videos,friends_videos,user_website,friends_website,email,manage_pages,publish_stream,read_stream,read_page_mailboxes,read_insights,ads_management"
});
fb.AccessToken = (string)result["access_token"];
return fb.AccessToken;
}
}
You can generate Short-Lived Token from Graph API Explorer.
Then you can extend it in Long-Lived Token from Access Token Debugger.
I do this every time.
It is said, that it is not possible to initiate new conversation through the API alone, except using Facebook's own Form integrated in the app. Is this correct, or is there some new API, which enables me to initiate a new conversation?
To reply to an existing conversation, I retrieved the conversations id using the following FQL Query "SELECT thread_id, . WHERE viewer_id={0} AND folder_id=0". Afterwards I retrieved the PageAccessToken for my app page using my user Access token, and tried to use this call:
*You can reply to a user's message by issuing an HTTP POST to /CONVERSATION_ID/messages with the following parameters [conversation id, message]. A conversation ID look like t_id.216477638451347.*
My POST Call looked like this (this is not a valid thread id): /t_id.2319203912/messages with message parameter filled. But it always said "Unknown method". Can you help me out with this one? Is there a parameter missing? I passed in the page's Access Token to call this one.
Is there some API out (except Facebook's Chat API), that I am missing, which can send private messages to users?
Edit:
What I wonder about is, that the code below only returns a single page, the application's page. Is this correct, or is there another page token required? This is what bugged me the most about the returned page.
The FacebookClient uses my UserToken to perform the next following task.
This is the code to retrieve my Page Access Token:
dynamic pageService = FacebookContext.FacebookClient.GetTaskAsync("/"+UserId+"/accounts").Result;
dynamic pageResult = pageService.data[0];
_pageId = pageResult["id"].ToString();
return pageResult["access_token"].ToString();
Now the code to retrieve my ConversationÍd:
dynamic parameters = new ExpandoObject();
parameters.q = string.Format("SELECT thread_id, folder_id, subject, recipients, updated_time, parent_message_id, parent_thread_id, message_count, snippet, snippet_author, object_id, unread, viewer_id FROM thread WHERE viewer_id={0} AND folder_id=0", FacebookContext.UserId);
dynamic conversations = FacebookContext.FacebookClient.GetTaskAsync("/fql",parameters).Result;
The following code is executed using the access token retrieved from the code above (page access token request).
Now the Code used to send the reply:
dynamic parameters = new ExpandoObject();
parameters.message = CurrentAnswer;
string taskString = "/t_id." + _conversationId + "/messages";
dynamic result = FacebookContext.FacebookClient.PostTaskAsync(taskString,parameters).Result;
return true;
I also tried it with facebook's graph API Debugger using the token, which is returned by my first part of code. But with the same error message.