1.1/search/tweets returns "Bad Authentication Data" with tmhOAuth


I have just pulled the latest version of tmhOAuth from Git, reset my Twitter API keys (which didn’t actually change them) and I still keep getting the 215 “Bad Authentication Data” error. The code I use, with the actual keys obviously, was taken from the tmhOAuthExamples repo and uses apponly_request() to indicate no action is performed on behalf of a user. This is somewhat equivalent to using request() with the (4th) $useauth param set to false. Neither one works.

I’m pretty much lost here. Any help would be much appreciated…

$tmhOAuth = new tmhOAuth(array(
‘consumer_key’ => ‘CONSUMER_KEY’,
‘consumer_secret’ => ‘CONSUMER_SECRET’,
‘user_token’ => ‘USER_TOKEN’,
‘user_secret’ => ‘USER_SECRET’,
‘curl_ssl_verifypeer’ => false

‘url’ => $tmhOAuth->url(‘1.1/search/tweets’),
‘params’ => array(
‘q’ => ‘%23hashtag’,
‘result_type’ => ‘recent’,
‘rpp’ => 10)

Response yielded:

array(1) {
array(1) {
array(2) {
string(23) “Bad Authentication data”


I’m trying to do the exact same thing. I’m not sure if I got a step further or if I’m going in the wrong direction, but I still have an issue.

I added the “bearer” attribute like so:

@$tmhOAuth = new tmhOAuth(array( 'consumer_key' => $tw_consumer_key, 'consumer_secret' => $tw_consumer_secret, 'token' => $tw_user_token, 'secret' => $tw_user_secret, 'bearer' => base64_encode($tw_consumer_key.':'.$tw_consumer_secret), ));

and now response is:

"errors":[{"message":"Invalid or expired token","code":89}]

I’ve tried everything I could think of. Anyone have ideas?

Here is the code I’m using:

$code = $tmhOAuth->apponly_request(array( 'url' => $tmhOAuth->url('1.1/search/tweets'), 'params' => array( 'q' => urlencode($q) ) ));

(this is on a page where $q is set to a search term)


Same issue What is that bearer key ?


It’s something I saw in the tmhoauth examples and in the twitter documentation. I believe you are supposed to build the key as described on https://dev.twitter.com/docs/auth/application-only-auth, and then request the oauth2 bearer token using this key. But the token request gives the same error.

I’m going to try a few different things and post the code later. Hopefully we can figure this out quickly.


YES! YAY! I figured it out!!!

I will post in a while what I did. What a headache! Now I have to take care of some work real quick, then I will post how I did it and go around the other discussions and let everyone know.


Please tell me from where will i get the tmhOAuth.php class


The tmhOAuth.php class is found here:

You can download the tmhOAuthExample class too, which extends tmhOAuth:

Just to clarify, I am running an apponly_request to search tweets. That is it, nothing more.

Getting authenticated is a two step process. The confusing part is that the API uses the same variable name for both: the bearer credentials to get the oauth2 token, and the bearer token which is the oauth2 token you get back.

First you have to request the oauth2 token (or bearer token) by using your encoded keys and secrets as the bearer token (or credentials).

Then, you can start a new request to search tweets by using the oauth2/bearer token instead of the encoded keys and secrets. Let me explain in more detail…

With minor changes (described below), I put all the tmhOAuth files and the tmhOAuthExample.php in a sub-folder on the site (I used /twitter). The files could go anywhere, but I like organization, and having them close to the root makes it easier to include.

The example class contains comments that say, “In production you shouldn’t use this file, but you could use the idea…”

However, I do not know what reason there is to not use this file.

I slightly modified tmhOAuthExample.php. Since this class extends the tmhOAuth, I replaced “tmhOAuthExample” text with “tmhOAuthExt”, and renamed the file to “tmhOAuthExt.php”.

I also replaced the location of “require” statements at the top of the file with a more simple require since the tmhOAuth.php is in the same folder and I am not using composer.
require ‘tmhOAuth.php’;

Then through trial and error, I came up with some code that I could put in a separate function to get the oauth2/bearer token.

function twitter_bearer_token( $tw_consumer_key, $tw_consumer_secret, $tw_user_token, $tw_user_secret ) { @$tmhOAuth = new tmhOAuthExt(array( 'consumer_key' => $tw_consumer_key, 'consumer_secret' => $tw_consumer_secret, 'token' => $tw_user_token, 'secret' => $tw_user_secret, 'bearer' => base64_encode($tw_consumer_key.':'.$tw_consumer_secret), 'curl_cainfo' => $_SERVER['DOCUMENT_ROOT'].'/twitter/cacert.pem', 'curl_capath' => $_SERVER['DOCUMENT_ROOT'].'/twitter/', ));
$bearer = $tmhOAuth->bearer_token_credentials();
$params = array(
    'grant_type' => 'client_credentials',

$code = $tmhOAuth->request(
    $tmhOAuth->url('/oauth2/token', null),
        'Authorization' => "Basic ${bearer}"

if ($code == 200) {
    $data = json_decode($tmhOAuth->response['response']);
    if (isset($data->token_type) && strcasecmp($data->token_type, 'bearer') === 0) {
        $new_bearer = $data->access_token;
} else {
    return $tmhOAuth->render_response();

return $new_bearer;


Now that we have a function to get the bearer token, here is the code I used to search tweets:

$tw_consumer_key = 'xxxxxxxxxxxxxxxxxxxxxx'; $tw_consumer_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; $tw_user_token = 'xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; $tw_user_secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';

// tmhoauth
require_once $_SERVER[‘DOCUMENT_ROOT’].’/twitter/tmhOAuthExt.php’;

$tw_bearer_token = twitter_bearer_token(

@$tmhOAuth = new tmhOAuthExt(array(
‘consumer_key’ => $tw_consumer_key,
‘consumer_secret’ => $tw_consumer_secret,
‘token’ => $tw_user_token,
‘secret’ => $tw_user_secret,
‘bearer’ => $tw_bearer_token,
‘curl_cainfo’ => $_SERVER[‘DOCUMENT_ROOT’].’/twitter/cacert.pem’,
‘curl_capath’ => $_SERVER[‘DOCUMENT_ROOT’].’/twitter/’,

// get tweets
$code = $tmhOAuth->apponly_request(array(
‘method’ => ‘GET’,
‘url’ => $tmhOAuth->url(‘1.1/search/tweets’),
‘params’ => array(
‘q’ => $q

// display tweets
if ($code == 200) {
// code to display tweets

I hope this helps a lot of people. Let me know if this needs any clarification.

Good luck!


Please get back to us on this :slight_smile:


Not there yet, but closest I’ve gotten using this. Thanks!


That works just fine. Thanks a bunch bro!


Thanks, It’s cool.


You are the man! This really helped me. I didn’t need to create the twitter_bearer_token funtion, as tmhOAuth comes with a ‘obtain_bearer.php’ file which does the same thing. I just used the code in there.

Thank you sooo much for your help!


you mention above two code files … which one you use for “bearer token”?