Missing required parameter: grant_type


#1

Hi all,

I’m trying to create a simple app to pull in tweets from different timelines and so am taking the Application Only Auth approach as per https://dev.twitter.com/docs/auth/application-only-auth

I’ve created the app and have keys/secrets/tokens coming out of my ears, all is going well. It seems that these are being accepted by https://api.twitter.com/oauth2/token as I’m getting an error back:

    [errors] => Array
        (
            [0] => stdClass Object
                (
                    [code] => 170
                    [label] => forbidden_missing_parameter
                    [message] => Missing required parameter: grant_type
                )

        )

I’ve tried sending the variable grant_type in a query and as an array through cURL but it just doesn’t see it and gives me this error every time!

Here is my PHP code:

	$url = "https://api.twitter.com/oauth2/token";
	$oauth_access_token = "XXXX";
	$oauth_access_token_secret = "XXXX";
	$consumer_key = "XXXX";
	$consumer_secret = "XXXX";
	$oauth = array( 'grant_type' => 'client_credentials');
	$headercreds = base64_encode($consumer_key.':'.$consumer_secret);

	$header =  "POST /oauth2/token HTTP/1.1\n";
	$header .= "Host: api.twitter.com\n";
	$header .= "User-Agent: Conscious Clients Feeds\n";
	$header .= "Authorization: Basic ".$headercreds."\n";
	$header .= "Content-Type: application/x-www-form-urlencoded;charset=UTF-8\n";
	$header .= "Content-Length: 29\n";

	// Make Requests
	$feed = curl_init();
	$header = array($header);
	$options = array( CURLOPT_HTTPHEADER => $header,
	                  CURLOPT_POSTFIELDS => http_build_query($oauth),
	                  CURLOPT_HEADER => 0,
	                  CURLOPT_POST => 1,
	                  CURLOPT_URL => $url,
	                  CURLOPT_RETURNTRANSFER => 1,
	                  CURLOPT_SSL_VERIFYPEER => 0 );

	
	curl_setopt_array($feed, $options);
	$json = curl_exec($feed);
	curl_close($feed);

	$twitter_data = json_decode($json);

Can you see any glaring problem with this code? As I said, I’ve tried passing the grant_type var as a query and as an array (removed http_build_query() from $oauth ).

Any help much appreciated!


#2

The “POST /oauth2/token HTTP/1.1\n” bit isn’t actually a HTTP header and is likely something you should leave up to the curl library to handle for you – perhaps your attachment of that is invalidating our ability to consider it as a valid POST request?


#3

Hi Taylor, thanks for the reply. I’ve made the change to the code as you suggested but it’s still giving me the same error back. Please can you have a look at my modified code and tell me what I might be doing wrong?

$url = "https://api.twitter.com/oauth2/token"; $oauth_access_token = "xxxx"; $oauth_access_token_secret = "xxxx"; $consumer_key = "xxxx"; $consumer_secret = "xxxx"; $oauth = array( 'grant_type' => 'client_credentials'); $data = "&grant_type=client_credentials"; $headercreds = base64_encode($consumer_key.':'.$consumer_secret);
// $header =  "POST /oauth2/token HTTP/1.1\n";
$header = "Content-Type: application/x-www-form-urlencoded;charset=UTF-8\n";
$header .= "Authorization: Basic ".$headercreds."\n";
$header .= "Host: api.twitter.com\n";
$header .= "User-Agent: Conscious Clients Feeds\n";
$header .= "Content-Length: 29\n";

// Make Requests
$feed = curl_init();
$header = array($header);
$options = array( CURLOPT_HTTPHEADER => $header,
                  CURLOPT_POSTFIELDS => $oauth,
                  CURLOPT_HEADER => 0,
                  CURLOPT_POST => 1,
                  CURLOPT_URL => $url,
                  CURLOPT_RETURNTRANSFER => 1,
                  CURLOPT_SSL_VERIFYPEER => 0 );

Thanks!


#4

I suggest using some of the curl library’s native functions – and also make sure you’re verifying peers with SSL (though unrelated to your issues). I’ve made a couple changes to your script that make it functional, for me at least:

$url = "https://api.twitter.com/oauth2/token";

$consumer_key = “xxx”;
$consumer_secret = “xxxx”;

$post_fields = ‘grant_type=client_credentials’;
// let’s use curl’s native ability to compose user credentials instead
$user_creds = $consumer_key .’:’ .$consumer_secret;

// headers are better organized an array, don’t worry about line endings
// curl should take care of the host & content-length headers for you

$header = array(
“Content-Type” => “application/x-www-form-urlencoded;charset=UTF-8”,
“User-Agent” => “Conscious Clients Feeds”);

// Make Requests
$feed = curl_init();
$header = array($header);
$options = array( CURLOPT_HTTPHEADER => $header,
CURLOPT_POSTFIELDS => $post_fields,
CURLOPT_USERPWD => $user_creds,
CURLOPT_HEADER => 0,
CURLOPT_POST => 1,
CURLOPT_VERBOSE => 1,
CURLOPT_URL => $url,
CURLOPT_SSL_VERIFYPEER => 1 // always verify peers with SSL
);
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
echo $json;
print $json;
$twitter_data = json_decode($json);


#5

Brilliant Taylor, that worked. Thank you for your help! My knowledge of cURL let me down quite badly there.

If it’s useful to anyone, the code I eventually got things working with to return the access token was:

$url = "https://api.twitter.com/oauth2/token";
$consumer_key = "xxxxx";
$consumer_secret = "xxxxx";
$user_creds = $consumer_key.':'.$consumer_secret;

$postfields = 'grant_type=client_credentials';

$header['Content-Type'] = "application/x-www-form-urlencoded;charset=UTF-8";
$header['User-Agent'] = "Your App Name";
$header['Authorization'] = "Basic ".$headercreds;
$header['Host'] = "api.twitter.com";

// Make Requests
$feed = curl_init();
$options = array( CURLOPT_HTTPHEADER => $header,
                  CURLOPT_POSTFIELDS => $postfields,
                  CURLOPT_USERPWD => $user_creds,
                  CURLOPT_HEADER => 0,
                  CURLOPT_POST => 1,
                  CURLOPT_VERBOSE => 1,
                  CURLOPT_URL => $url,
                  CURLOPT_SSL_VERIFYPEER => 0 );


curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);

$twitter_data = json_decode($json);
print_r($twitter_data);

#6

Hi Taylor, please can I ask for your help again?

I’m now up to part 3 on the guide https://dev.twitter.com/docs/auth/application-only-auth, so now trying to authenticate API requests with the bearer token. I’ve added the code below but I’m getting 215 Bad Authentication Data:

// Authorize using bearer token $url = "https://api.twitter.com/1.1/statuses/user_timeline.json"; $get = "?screen_name=conscious_sol&count=2"; $header['Content-Type'] = "application/json; charset=utf-8"; $header['Authorization'] = "Bearer ".$output->access_token;
$feed = curl_init();
$options = array( CURLOPT_HTTPHEADER => $header,
                  CURLOPT_HEADER => 0,
                  CURLOPT_CUSTOMREQUEST => 'GET',
                  CURLOPT_POST => 0,
                  CURLOPT_VERBOSE => 1,
                  CURLOPT_URL => $url.$get,
                  CURLOPT_SSL_VERIFYPEER => 0,
                  CURLOPT_SSL_VERIFYHOST => 0,
                  CURLOPT_RETURNTRANSFER => 1 );


curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
$output = json_decode($json);

Here, $output->access_token is the token exactly as-is, returned from the previous part.

Please can you advise?


#7

My rusty PHP led you a little astray :slight_smile: The HTTP header array gets initiialized a little differently than I remembered. Try something more like this… (note that the screen name you’re lookup doesn’t belong to an actual user…)

// Authorize using bearer token $url = "https://api.twitter.com/1.1/statuses/user_timeline.json"; $get = "?screen_name=conscious_sol&count=2"; $final_url = $url . $get; # do not set a Content-Type on a GET-based request. Only when sending data. $auth_header = "Authorization: Bearer " . $output->access_token; $header = array($auth_header); // should be an array of prepared strings with k/v pairs instead

$feed = curl_init();
$options = array( CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => 1,
# not needed, GET is default
// CURLOPT_CUSTOMREQUEST => ‘GET’,
CURLOPT_POST => 0,
CURLOPT_VERBOSE => 1,
CURLOPT_URL => $final_url,
CURLOPT_SSL_VERIFYPEER => 1, // remember to do this :slight_smile:
CURLOPT_RETURNTRANSFER => 0 );

curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
$output = json_decode($json);


#8

Once again Taylor, many thanks. That works well.

I modified it slightly to return an array of tweets so here’s the code I ended up with, for anyone who might find it useful:

// Authorize using bearer token $url = "https://api.twitter.com/1.1/statuses/user_timeline.json"; $get = "?screen_name=twitterapi&count=2"; $auth_header = "Authorization: Bearer ".$output->access_token; $header = array($auth_header);

$feed = curl_init();
$options = array( CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => 0,
CURLOPT_POST => 0,
CURLOPT_VERBOSE => 1,
CURLOPT_URL => $url.$get,
CURLOPT_SSL_VERIFYPEER => 1,
CURLOPT_RETURNTRANSFER => 1 );

curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
$twitterfeed = json_decode($json,true);