Instagram Documentation: https://instagram.com/developer/secure-api-requests/
Goal: Comply with the [now mandatory] Enforce Signed Requests feature using Instagram API.
Functional issue: without compliance IG Like limits are 30 per hour. Complying allows for 100 Likes per hour
Technical issue: The following error is returned when making a simple call to the API for media:
{"code": 403, "error_type": "OAuthForbiddenException", "error_message": "Invalid signed-request: Signature does not match"}
Instagram Client Set Up: Client ID, Client Secret, Redirect URI have all been verified to match those used in all portions of the PHP code. Both "Disable implicit OAuth" and "Enforce signed requests" are checked.
Code Explanation: Three distinct pieces of code are needed to create the handshake with IG: 1. Header 2. Access Token [i.e. "access_token"] 3. Call with Sig [i.e. "sig" - not to be confused with "signature"]. I have confirmed that the same client_id, client_secret and access_token are used throughout all pieces of code. NOTE: Parts 1 and 2 work[ed] fine prior to the mandatory compliance. They still work fine, but I only get 30 Likes/hr [i.e. the main functional issue]
Header Code:
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$this->signature = $ip .'|'. hash_hmac('sha256', $ip, $this->settings['client_secret'], false);
Access Token Code, which returns successfully with an array similar to {"access_token":"11deadbee7.7dded5e.c0d656eead134218beef31a61b45e4d9",...}
$apiData = array(
'grant_type' => 'authorization_code',
'client_id' => $this->getApiKey(),
'client_secret' => $this->getApiSecret(),
'redirect_uri' => $this->getApiCallback(),
'code' => $code
);
$ch = curl_init();
$xHeaderFront = 'X-Insta-Forwarded-For:';
$xHeader = $xHeaderFront.$this->signature;
curl_setopt($ch, CURLOPT_URL, $apiHost);
curl_setopt($ch, CURLOPT_POST, count($apiData));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($apiData));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$jsonData = curl_exec($ch);
curl_close($ch);
Call with Sig. This returns the error {"code": 403, "error_type": "OAuthForbiddenException", "error_message": "Invalid signed-request: Signature does not match"}:
$params = array(); //temporary to force a simple set of parameters
$params['count']=10;
$params['access_token'] = $this->getAccessToken(); //11deadbee7.7dded5e.c0d656eead134218beef31a61b45e4d9 masked, but kept for ease of comparison]
$endpoint = '/media/657988443280050001_25025320'; //temporary
$sig = $endpoint;
ksort($params);
foreach ($params as $key => $val) {
$sig .= "|$key=$val";
}
$enforcedSig = hash_hmac('sha256', $sig, $secret, false);
$apiCall = 'https://api.instagram.com/v1/media/657988443280050001_25025320/likes?sig='.$enforcedSig.'&count=10&access_token='.$params['access_token'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $apiCall);
$xHeaderFront = 'X-Insta-Forwarded-For:';
$xHeader = $xHeaderFront.$this->signature;
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Accept: application/json',$xHeader));
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$jsonData = curl_exec($ch);
curl_close($ch);
Your $endpoint seems to be wrong.
Add "/likes".
$endpoint = '/media/657988443280050001_25025320/likes'; //temporary