[php] Twitter API returns error 215, Bad Authentication Data

I am trying to call following Twitter's API to get a list of followers for a user.

http://api.twitter.com/1.1/followers/ids.json?cursor=-1&screen_name=username

And I am getting this error message in response.

{
    code = 215;
    message = "Bad Authentication data";
}

I can't seem to find the documentation related to this error code. Anyone has any idea about this error?

This question is related to php api twitter

The answer is


A very concise code without any other php file include of oauth etc. Please note to obtain following keys you need to sign up with https://dev.twitter.com and create application.

<?php
$token = 'YOUR_TOKEN';
$token_secret = 'YOUR_TOKEN_SECRET';
$consumer_key = 'CONSUMER_KEY';
$consumer_secret = 'CONSUMER_SECRET';

$host = 'api.twitter.com';
$method = 'GET';
$path = '/1.1/statuses/user_timeline.json'; // api call path

$query = array( // query parameters
    'screen_name' => 'twitterapi',
    'count' => '5'
);

$oauth = array(
    'oauth_consumer_key' => $consumer_key,
    'oauth_token' => $token,
    'oauth_nonce' => (string)mt_rand(), // a stronger nonce is recommended
    'oauth_timestamp' => time(),
    'oauth_signature_method' => 'HMAC-SHA1',
    'oauth_version' => '1.0'
);

$oauth = array_map("rawurlencode", $oauth); // must be encoded before sorting
$query = array_map("rawurlencode", $query);

$arr = array_merge($oauth, $query); // combine the values THEN sort

asort($arr); // secondary sort (value)
ksort($arr); // primary sort (key)

// http_build_query automatically encodes, but our parameters
// are already encoded, and must be by this point, so we undo
// the encoding step
$querystring = urldecode(http_build_query($arr, '', '&'));

$url = "https://$host$path";

// mash everything together for the text to hash
$base_string = $method."&".rawurlencode($url)."&".rawurlencode($querystring);

// same with the key
$key = rawurlencode($consumer_secret)."&".rawurlencode($token_secret);

// generate the hash
$signature = rawurlencode(base64_encode(hash_hmac('sha1', $base_string, $key, true)));

// this time we're using a normal GET query, and we're only encoding the query params
// (without the oauth params)
$url .= "?".http_build_query($query);
$url=str_replace("&amp;","&",$url); //Patch by @Frewuill

$oauth['oauth_signature'] = $signature; // don't want to abandon all that work!
ksort($oauth); // probably not necessary, but twitter's demo does it

// also not necessary, but twitter's demo does this too
function add_quotes($str) { return '"'.$str.'"'; }
$oauth = array_map("add_quotes", $oauth);

// this is the full value of the Authorization line
$auth = "OAuth " . urldecode(http_build_query($oauth, '', ', '));

// if you're doing post, you need to skip the GET building above
// and instead supply query parameters to CURLOPT_POSTFIELDS
$options = array( CURLOPT_HTTPHEADER => array("Authorization: $auth"),
                  //CURLOPT_POSTFIELDS => $postfields,
                  CURLOPT_HEADER => false,
                  CURLOPT_URL => $url,
                  CURLOPT_RETURNTRANSFER => true,
                  CURLOPT_SSL_VERIFYPEER => false);

// do our business
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);

$twitter_data = json_decode($json);


foreach ($twitter_data as &$value) {
   $tweetout .= preg_replace("/(http:\/\/|(www\.))(([^\s<]{4,68})[^\s<]*)/", '<a href="http://$2$3" target="_blank">$1$2$4</a>', $value->text);
   $tweetout = preg_replace("/@(\w+)/", "<a href=\"http://www.twitter.com/\\1\" target=\"_blank\">@\\1</a>", $tweetout);
   $tweetout = preg_replace("/#(\w+)/", "<a href=\"http://search.twitter.com/search?q=\\1\" target=\"_blank\">#\\1</a>", $tweetout);
}

echo $tweetout;

?>

Regards


The only solution I've found so far is:

  • Create application in twitter developer panel
  • Authorize user with your application (or your application in user account) and save "oauth_token" and "oauth_token_secret" which Twitter gives you. Use TwitterOAuth library for this, it's pretty easy, see examples coming with library.
  • Using this tokens you can make authenticated requests on behalf of user. You can do it with the same library.

    // Arguments 1 and 2 - your application static tokens, 2 and 3 - user tokens, received from Twitter during authentification  
    $connection = new TwitterOAuth(TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET, $tokens['oauth_token'], $tokens['oauth_token_secret']);  
    $connection->host = 'https://api.twitter.com/1.1/'; // By default library uses API version 1.  
    $friendsJson = $connection->get('/friends/ids.json?cursor=-1&user_id=34342323');  
    

This will return you list of user's friends.


You need to send customerKey and customerSecret to Zend_Service_Twitter

$twitter = new Zend_Service_Twitter(array(
                'consumerKey' => $this->consumer_key,
                'consumerSecret' => $this->consumer_secret,
                'username' => $user->screenName,
                'accessToken' => unserialize($user->token)
));

After two days of research I finally found that to access s.o. public tweets you just need any application credentials, and not that particular user ones. So if you are developing for a client, you don't have to ask them to do anything.

To use the new Twitter API 1.1 you need two things:

First, you can (actually have to) create an application with your own credentials and then get the Access token (OAUTH_TOKEN) and Access token secret (OAUTH_TOKEN_SECRET) from the "Your access token" section. Then you supply them in the constructor for the new TwitterOAuth object. Now you can access anyone public tweets.

$connection = new TwitterOAuth( CONSUMER_KEY, CONSUMER_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET );

$connection->host = "https://api.twitter.com/1.1/"; // change the default
$connection->ssl_verifypeer = TRUE;
$connection->content_type = 'application/x-www-form-urlencoded';

$tweets = $connection->get('http://api.twitter.com/1.1/statuses/user_timeline.json?screen_name='.$username.'&count='.$count);

Actually I think this is what Pavel has suggested also, but it is not so obvious from his answer.

Hope this saves someone else those two days :)


Be sure that you have read AND write access for application in twitter


I was facing the same problem all the time the only solution I figurae out is typing CONSUMER_KEY and CONSUMER_SECRET directly to new TwitterOAuth class defination .

$connection = new TwitterOAuth(  "MY_CK" , "MY_CS"  );

Don't use variable or statics on this and see if the issue sloved .


The url with /1.1/ in it is correct, it is the new Twitter API Version 1.1.

But you need an application and authorize your application (and the user) using oAuth.

Read more about this on the Twitter Developers documentation site :)


This might help someone who use Zend_Oauth_Client to work with twitter api. This working config:

$accessToken = new Zend_Oauth_Token_Access();
$accessToken->setToken('accessToken');
$accessToken->setTokenSecret('accessTokenSecret');

$client = $accessToken->getHttpClient(array(
    'requestScheme' => Zend_Oauth::REQUEST_SCHEME_HEADER,
    'version' => '1.0', // it was 1.1 and I got 215 error.
    'signatureMethod' => 'HMAC-SHA1',
    'consumerKey' => 'foo',
    'consumerSecret' => 'bar',
    'requestTokenUrl' => 'https://api.twitter.com/oauth/request_token',
    'authorizeUrl' => 'https://api.twitter.com/oauth/authorize',
    'accessTokenUrl' => 'https://api.twitter.com/oauth/access_token',
    'timeout' => 30
));

It look like twitter api 1.0 allows oauth version to be 1.1 and 1.0, where twitter api 1.1 require only oauth version to be 1.0.

P.S We do not use Zend_Service_Twitter as it does not allow send custom params on status update.


The answer by Gruik worked for me in the below thread.

{Excerpt | Zend_Service_Twitter - Make API v1.1 ready}

with ZF 1.12.3 the workaround is to pass consumerKey and consumerSecret in oauthOptions option, not directrly in the options.

    $options = array(
        'username' => /*...*/,
        'accessToken' => /*...*/,
        'oauthOptions' => array(
            'consumerKey' => /*...*/,
            'consumerSecret' => /*...*/,
        )
    );

Try this twitter API explorer, you can sign in as a developer and query whatever you want.


I'm using HybridAuth and was running into this error connecting to Twitter. I tracked it down to (me) sending Twitter an incorrectly cased request type (get/post instead of GET/POST).

This would cause a 215:

$call = '/search/tweets.json';
$call_type = 'get';
$call_args = array(
    'q'           => 'pancakes',
    'count'       => 5,
);
$response = $provider_api->api( $call, $call_type, $call_args );

This would not:

$call = '/search/tweets.json';
$call_type = 'GET';
$call_args = array(
    'q'           => 'pancakes',
    'count'       => 5,
);
$response = $provider_api->api( $call, $call_type, $call_args );

Side note: In the case of HybridAuth the following also would not (because HA internally provides the correctly-cased value for the request type):

$call = '/search/tweets.json';
$call_args = array(
    'q'           => 'pancakes',
    'count'       => 5,
);
$response = $providers['Twitter']->get( $call, $call_args );

UPDATE: Twitter API 1 is now deprecated. Refer to above answer.

Twitter 1.1 does not work with that syntax (when I wrote this answer). Needs to be 1, not 1.1. This will work:

http://api.twitter.com/1/followers/ids.json?cursor=-1&screen_name=username


FOUND A SOLUTION - using the Abraham TwitterOAuth library. If you are using an older implementation, the following lines should be added after the new TwitterOAuth object is instantiated:

$connection->host = "https://api.twitter.com/1.1/";
$connection->ssl_verifypeer = TRUE;
$connection->content_type = 'application/x-www-form-urlencoded';

The first 2 lines are now documented in Abraham library Readme file, but the 3rd one is not. Also make sure that your oauth_version is still 1.0.

Here is my code for getting all user data from 'users/show' with a newly authenticated user and returning the user full name and user icon with 1.1 - the following code is implemented in the authentication callback file:

session_start();
require ('twitteroauth/twitteroauth.php');
require ('twitteroauth/config.php');

$consumer_key = '****************';
$consumer_secret = '**********************************';

$to = new TwitterOAuth($consumer_key, $consumer_secret);

$tok = $to->getRequestToken('http://exampleredirect.com?twitoa=1');

$token = $tok['oauth_token'];
$secret = $tok['oauth_token_secret'];

//save tokens to session
$_SESSION['ttok'] = $token;
$_SESSION['tsec'] = $secret;

$request_link = $to->getAuthorizeURL($token,TRUE);

header('Location: ' . $request_link);

The following code then is in the redirect after authentication and token request

if($_REQUEST['twitoa']==1){
    require ('twitteroauth/twitteroauth.php');
    require_once('twitteroauth/config.php');
    //Twitter Creds
    $consumer_key = '*****************';
    $consumer_secret = '************************************';

    $oauth_token = $_GET['oauth_token']; //ex Request vals->http://domain.com/twitter_callback.php?oauth_token=MQZFhVRAP6jjsJdTunRYPXoPFzsXXKK0mQS3SxhNXZI&oauth_verifier=A5tYHnAsbxf3DBinZ1dZEj0hPgVdQ6vvjBJYg5UdJI

    $ttok = $_SESSION['ttok'];
    $tsec = $_SESSION['tsec'];

    $to = new TwitterOAuth($consumer_key, $consumer_secret, $ttok, $tsec);
    $tok = $to->getAccessToken();
    $btok = $tok['oauth_token'];
    $bsec = $tok['oauth_token_secret'];
    $twit_u_id = $tok['user_id'];
    $twit_screen_name = $tok['screen_name'];

    //Twitter 1.1 DEBUG
    //print_r($tok);
    //echo '<br/><br/>';
    //print_r($to);
    //echo '<br/><br/>';
    //echo $btok . '<br/><br/>';
    //echo $bsec . '<br/><br/>';
    //echo $twit_u_id . '<br/><br/>';
    //echo $twit_screen_name . '<br/><br/>';

    $twit_screen_name=urlencode($twit_screen_name);
    $connection = new TwitterOAuth($consumer_key, $consumer_secret, $btok, $bsec);
    $connection->host = "https://api.twitter.com/1.1/";
    $connection->ssl_verifypeer = TRUE;
    $connection->content_type = 'application/x-www-form-urlencoded';
    $ucontent = $connection->get('users/show', array('screen_name' => $twit_screen_name));

    //echo 'connection:<br/><br/>';
    //print_r($connection);
    //echo '<br/><br/>';
    //print_r($ucontent);

    $t_user_name = $ucontent->name;
    $t_user_icon = $ucontent->profile_image_url;

    //echo $t_user_name.'<br/><br/>';
    //echo $t_user_icon.'<br/><br/>';
}

It took me way too long to figure this one out. Hope this helps someone!!


I know that this is old but yesterday I faced the same issue when calling this URL using C# and the HttpClient class with the Bearer authentication token:

http://api.twitter.com/1.1/followers/ids.json?cursor=-1&screen_name=username

It turns out that the solution for me was to use HTTPS instead of HTTP. So my URL would look like this:

https://api.twitter.com/1.1/followers/ids.json?cursor=-1&screen_name=username

So here is a snippet of my code:

            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://api.twitter.com/1.1/");
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Add("Authorization", "Bearer **** YOUR BEARER TOKEN GOES HERE ****");

                var response = client.GetAsync("statuses/user_timeline.json?count=10&screen_name=username").Result;
                if (!response.IsSuccessStatusCode)
                {
                    return result;
                }
                var items = response.Content.ReadAsAsync<IEnumerable<dynamic>>().Result;
                foreach (dynamic item in items)
                {
                    //Do the needful
                }
            }

Here first every one need to use oauth2/token api then use followers/list api.
Other wise you will get this error. Because followers/list api requires Authentication.

In swift (for mobile app) me also got the same problem.

If you want to know the api's and it's parameters follow this link , Get twitter friends list in swift?


Examples related to php

I am receiving warning in Facebook Application using PHP SDK Pass PDO prepared statement to variables Parse error: syntax error, unexpected [ Preg_match backtrack error Removing "http://" from a string How do I hide the PHP explode delimiter from submitted form results? Problems with installation of Google App Engine SDK for php in OS X Laravel 4 with Sentry 2 add user to a group on Registration php & mysql query not echoing in html with tags? How do I show a message in the foreach loop?

Examples related to api

I am receiving warning in Facebook Application using PHP SDK Couldn't process file resx due to its being in the Internet or Restricted zone or having the mark of the web on the file Failed to load resource: the server responded with a status of 404 (Not Found) css Call another rest api from my server in Spring-Boot How to send custom headers with requests in Swagger UI? This page didn't load Google Maps correctly. See the JavaScript console for technical details How can I send a Firebase Cloud Messaging notification without use the Firebase Console? Allow Access-Control-Allow-Origin header using HTML5 fetch API How to send an HTTP request with a header parameter? Laravel 5.1 API Enable Cors

Examples related to twitter

Twitter - How to embed native video from someone else's tweet into a New Tweet or a DM How to get user's high resolution profile picture on Twitter? How to extract hours and minutes from a datetime.datetime object? Incorrect string value: '\xF0\x9F\x8E\xB6\xF0\x9F...' MySQL Twitter - share button, but with image How to access elements of a JArray (or iterate over them) Simplest PHP example for retrieving user_timeline with Twitter API version 1.1 Twitter API returns error 215, Bad Authentication Data bower command not found How do I fix twitter-bootstrap on IE?