2

Error Message

Client error: POST https://api.twitter.com/oauth/request_token resulted in a 400 Bad Request response: {"errors":[{"code":215,"message":"Bad Authentication data."}]}

Extract Token from Twitter

$method = "POST";
$endpoint = "https://api.twitter.com/oauth/request_token";
$authorizationParams = [
    "oauth_callback" => "url, this matches with Callback URI of api info",
    "oauth_consumer_key" => "my api key",
    "oauth_nonce" => md5(microtime(). mt_rand()),
    "oauth_signature_method" => "HMAC-SHA1",
    "oauth_timestamp" => time(),
    "oauth_version" => "1.0"
];

$authorizationParams["oauth_signature"] = $this->GetSignature($method, $endpoint, $authorizationParams);
$authorizationString = $this->getAuthorizationString($authorizationParams);

Post Request to Twitter

$client = new \GuzzleHttp\Client();
$response = $client->request('POST', $endpoint, [
    'headers' => [
        'Content-Type' => 'application/json',
        "Authorization: OAuth " . $authorizationString
    ]
]);
$result = json_decode($response->getBody(), true);

Signature generation

private function GetSignature($method, $endpoint, $authorizationParams) {
    $twitter_conf = \Config::get('twitter');
    uksort($authorizationParams, "strcmp");
    foreach($authorizationParams as $key => $value) {
        $authorizationParams[$key] = rawurlencode($key) . "=" . rawurlencode($value);
    }
    
    $signatureBase = [
        rawurlencode($method),
        rawurlencode($endpoint),
        rawurlencode(implode("&", $authorizationParams)),
    ];
    
    $signatureBaseString = implode("&", $signatureBase);
    $signatureKey = [
        rawurlencode($twitter_conf["secret"]),
        ""
    ];
    
    $signatureKeyString = implode("&", $signatureKey);
    
    return base64_encode(hash_hmac("sha1", $signatureBaseString, $signatureKeyString, true));
}

Convert array to string

private function getAuthorizationString($authorizationParams) {
    $authorizationString = "";
    $count = 0;
    foreach($authorizationParams as $key => $value) {
        $authorizationString .= $count == 0 ? "" : ",";
        $authorizationString .= rawurlencode($key) . '="' . rawurlencode($value) . '"';
        $count++;
    }
    return $authorizationString;
}
Pankaj
  • 9,749
  • 32
  • 139
  • 283
  • It says *Bad Authentication data.* did you check auth?. https://stackoverflow.com/questions/17143985/twitter-api-error-215 – Abdulla Nilam Oct 03 '22 at 11:57
  • Thanks for the reply. My question is about request token only. I saw that you have suggested user timeline. I saw that link. but did not help – – Pankaj Oct 03 '22 at 13:10
  • Why don't you use a [Twitter client](https://developer.twitter.com/en/docs/twitter-api/tools-and-libraries/v2#php)? – Olivier Oct 08 '22 at 06:44

1 Answers1

0

You appear to passing the "oauth_callback" value as part of the header. According to https://developer.twitter.com/en/docs/authentication/api-reference/request_token, "oauth_callback" should be passed as a query string as part of the endpoint URL.

Try something like this instead:

$CALLBACK_URL = urlencode( "url, this matches with Callback URI of api info" );
$method = "POST";
$endpoint = "https://api.twitter.com/oauth/request_token?oauth_callback=$CALLBACK_URL";
$authorizationParams = [
    "oauth_consumer_key" => "my api key",
    "oauth_nonce" => md5(microtime(). mt_rand()),
    "oauth_signature_method" => "HMAC-SHA1",
    "oauth_timestamp" => time(),
    "oauth_version" => "1.0"
];

$authorizationParams["oauth_signature"] = $this->GetSignature($method, $endpoint, $authorizationParams);
$authorizationString = $this->getAuthorizationString($authorizationParams);

When modifying the request to the above, make sure you modify the signature. Here's an example of how my application signs requests. Take note of the fact that it's extracting the endpoint URL's query string and encoding it into the signature. Your signing method does not do this and will likely return a bad signature. Also note, that the endpoint URL has been stripped of the same query portion in the base string to be used for generating the hash.

function generateSignature( $method, $url, $params = [] ) {
        $parts = parse_url( $url );

        // We need to normalize the endpoint URL
        $scheme = isset( $parts['scheme'] ) ? $parts['scheme'] : 'http';
        $host = isset( $parts['host'] ) ? $parts['host'] : '';
        $port = isset( $parts['port'] ) ? $parts['port'] : ( $scheme == 'https' ? '443' : '80' );
        $path = isset( $parts['path'] ) ? $parts['path'] : '';
        if( ( $scheme == 'https' && $port != '443' ) ||
            ( $scheme == 'http' && $port != '80' )
        ) {
            // Only include the port if it's not the default
            $host = "$host:$port";
        }

        // Also the parameters
        $pairs = [];
        parse_str( isset( $parts['query'] ) ? $parts['query'] : '', $query );
        $query += $params;
        unset( $query['oauth_signature'] );
        if( $query ) {
            $query = array_combine(
            // rawurlencode follows RFC 3986 since PHP 5.3
                array_map( 'rawurlencode', array_keys( $query ) ),
                array_map( 'rawurlencode', array_values( $query ) )
            );
            ksort( $query, SORT_STRING );
            foreach( $query as $k => $v ) {
                $pairs[] = "$k=$v";
            }
        }

        $toSign = rawurlencode( strtoupper( $method ) ) . '&' .
                  rawurlencode( "$scheme://$host$path" ) . '&' .
                  rawurlencode( join( '&', $pairs ) );
        $key = rawurlencode( CONSUMERSECRET ) . '&' .
               rawurlencode( ( isset( ACCESSTOKENSECRET ) ?
                   ACCESSTOKENSECRET :
                   ( isset( REQUESTTOKENSECRET ) ? REQUESTTOKENSECRET :
                       "" ) )
               );

        return base64_encode( hash_hmac( 'sha1', $toSign, $key, true ) );
    }
Cyberpower678
  • 159
  • 1
  • 13