How to properly generate Facebook Graph API App Secret Proof in Javascript

I am making a server side Facebook Graph API call to the all_mutual_friends edge: https://developers.facebook.com/docs/graph-api/reference/user-context/all_mutual_friends/

The call works when the two users are friends, but returns no useful data when they users aren't friends. According to the docs, this is because I must sign the call with the appsecret_proof parameter. No matter what I try, I am not able to successfully pass this parameter. I am using jsrsasign running on Parse. I have tried every configuration of using the access token as the message and my appSecret as the key, and vice versa. I have also tried multiple combinations of utf8 and hex. Every time I receive the error: invalid appsecret_proof provided in the API argument

Code:

  var Signer = require("cloud/vendor/jsrsasign/lib/jsrsasign.js");
  var userId = request.params.userId;
  var accessToken = request.params.accessToken;
  var appSecret = "redactedStringPastedFromFacebook";

  var signer = new Signer.Mac({alg: "hmacsha256", pass: appSecret});
  var appSecretString = signer.doFinalString(accessToken);
  var appSecretHex = signer.doFinalHex(accessToken);

  var graphRequestURL = "https://graph.facebook.com/v2.5/" + userId;
  var fields = "?fields=context.fields(all_mutual_friends.fields(name,picture.width(200).height(200)))";
  //var authorization = "&access_token=" + accessToken; //this works, but only for existing friends
  var authorization = "&access_token=" + accessToken + "&appsecret_proof=" + appSecretHex;
  return Parse.Cloud.httpRequest({
    url: graphRequestURL + fields + authorization,
    method: "GET",
  })

Most examples I have seen are in PHP or Python and the crypto routines are a bit more clear. This works in that both appSecretString and appSecretHex don't throw errors and look reasonable, however the values are always rejected by Facebook.

Notes:

  • I have triple checked the App Secret value provided by Facebook
  • I have been approved by Facebook to use the all_mutual_friends feature, which is a requirement for this particular call
  • I am using Parse, which isn't Node, and can't use NPM modules that have external dependencies, which is why I am using jsrsasign. I also tried using CryptoJS directly, but it is no longer maintained and doesn't have proper module support and jsrsasign seems to wrap it anyway.

Answers


Here it is:

  import cryptojs from 'crypto-js';

  const accessToken = <your_page_access_token>;
  const clientSecret = <your_app_client_secret>;
  const appsecretProof = CryptoJS.HmacSHA256(accessToken, clientSecret).toString(CryptoJS.enc.Hex);

Need Your Help

PHP form sending duplicate emails

javascript php html contact-form

I have a PHP contact form, it was working pretty well, but now my client says it's duplicating or even sending 4-5 times the contact email, my client says that it's taking too long to show the resp...

Take database entry with URL and title and show on page

ruby-on-rails

I have a profile form that takes a URL as an entry.