2

I was following Instagram API Basic Display documentation. I've created Facebook App, configured Instagram Basic Display, added Test User, Authenticated the Test User using GET request:

https://api.instagram.com/oauth/authorize
  ?app_id={app-id}
  &redirect_uri={redirect-uri}
  &scope=user_profile,user_media
  &response_type=code

But when I try to request access_token using POST request from the documentation: I receive ERROR 400 with message "You must provide a client_id". However, documentation says nothing about client_id and Instagram Basic Display doesn't provide client_id.

enter image description here

What am I doing wrong? Has any of you had similar problem?

VitFL
  • 106
  • 10
  • Why do you have the app_id in the URL _and_ in your POST parameters? (App id and client id should be the same thing, they are just not consistent with the phrasing AFAIK.) – 04FS Nov 29 '19 at 07:51
  • @04FS, its just how Postman works, when u enter Query Params, it displays them in URI. But my question was, why "Instagram API Basic Display" want this client_id at all? There is no client_id if u create instagram app in at https://developers.facebook.com/ And if u ready their documentation, it clearly says just to send app_id and app_secret. – VitFL Nov 29 '19 at 09:47
  • As I said, both app id and client id get used as synonyms by Facebook. – 04FS Nov 29 '19 at 09:53
  • 2
    You are simply not sending the POST parameters properly here. These should not be entered on the Params tab (that actually creates query string parameters, and _that_ is why they are shown as part of the URL), but on the Body tab instead, with encoding `x-www-form-urlencoded` – 04FS Nov 29 '19 at 09:55
  • Thanks :) You are right! However, now I'm getting ""error_message": "Matching code was not found or was already used"". And I am using freshly generated code. Now i'm trying to figure out why. – VitFL Nov 29 '19 at 10:10
  • Since you are presumably fishing out the code value manually here from the URL you got redirected to – did you pay attention to what the documentation says about the `#_` part of that URL …? – 04FS Nov 29 '19 at 10:17
  • Yea, I am removing #_ from the end of URL. – VitFL Nov 29 '19 at 10:17
  • It can really rather only by one of those two things - either the code was used already (unlikely, when you are testing manually), or the value you are sending is not correct. – 04FS Nov 29 '19 at 10:20
  • Getting the Authorization Code is very simple because the browser is actually redirecting. What is not clear and obvious from the documentation is how the data is to be formatted. To make matters worse the returned error messages are somehow generic and somehow meaningless when taken into context. Like "You must provide a client_id" when in actual fact you requesting the access token using app_id. – patJnr Dec 12 '19 at 12:08
  • https://stackoverflow.com/questions/59526137/my-app-was-rejected-by-instagram-basic-display-api-review-due-to-invalid-reasons – Amrut Bidri Dec 30 '19 at 06:30

2 Answers2

3

You should make a POST request to https://api.instagram.com/oauth/access_token with the parameters in the body, NOT the Params. Make sure that the "x-www-form-urlencoded" option is enable.

enter image description here

See a more detailed answer here: https://stackoverflow.com/a/60851414/1908112

Anas
  • 1,345
  • 14
  • 15
1

I managed to get mine working by using GuzzleHttp\Client like this.

Step 1. get the Authorization Code $code

Step 2. Get the short-lived AccessToken

Short-Lived Access tokens are valid for just 1 hour.

$aAccessToken = $this->fetchAccessToken( $code );
$short_lived_access_token = $aAccessToken[ 'access_token' ];
$user_id                  = $aAccessToken[ 'user_id' ];

Step 3 (optional)

If you want the Long-Lived token, which is valid for 60days, you can immediately exchange the $short_lived_access_token.

$aLongLivedTokenResult   =           = $this->GetLongLivedToken( $short_lived_access_token );
$long_lived_access_token = $aLongLivedTokenResult[ 'access_token' ];
$expires_in = $aLongLivedTokenResult[ 'expires_in' ];

long_lived_access_token and expires_in can be saved and when the token has expired after 60 days you can refresh it.

Step 4 Now you can fetch the user media like this.

Bear in mind that the long_lived_access_token expires and before you FETCH you should actually check if the token has expired and if it has, exchange it to get a new one. And the token recycling begins.

    $aQueryString = [
        'fields'       => 'id,media_url,permalink,timestamp,caption',
        'access_token' => $long_lived_access_token,

    ];
    $uri = 'https://graph.instagram.com/{$user_id}/media?' . http_build_query( $aQueryString ) );

//functions

Because the fetchAccessToken function uses the POST method, Adding content-type = application/x-www-form-urlencoded on the headers alone didn't really work. form_params on the options did the trick for me.

private function fetchAccessToken(){
    $aOptions = [
      'app_id'       => $this->provider->AppID,
      'app_secret'   => $this->provider->AppSecret,
      'grant_type'   => 'authorization_code',
      'redirect_uri' => $this->provider->getRedirectUri(),
      'code'         => $accessCode,       
    ];

    $client   = new Client( [
        'base_uri' => 'https://api.instagram.com',
        'headers'  => [
            'content-type' => 'application/x-www-form-urlencoded',
        ],
    ] );


    $response = $client->request( 'POST', 'oauth/access_token', [
        'form_params' => $aOptions,
    ] );
    return json_decode( $response->getBody(), true );

}

private function GetLongLivedToken( $access_token )
{

    $aOptions = [
        'grant_type'    => 'ig_exchange_token',
        'client_secret' => $this->provider->AppSecret,
        'access_token'  => $access_token,

    ];

    $response =  new Client( [
        'base_uri' => 'https://graph.instagram.com',
    ] )->request( 'GET', 'access_token?' . http_build_query( $aOptions ) );

    $stream   = $response->getBody();
    $contents = $stream->getContents();
    return json_decode( $contents, true ); 

}
patJnr
  • 174
  • 1
  • 8