I found a library online to get started with Twitter OAuth and it gets me connected, and able to pull down some data from Twitter. I save the tokens to a session (I will be putting them into a database for production, but I'm just trying to get the basics for now). The problem comes when I change to a different page and am no longer able to make API calls.
Here is my code:
(If my brackets don't exactly match here, it's because I stripped the twitter portion out to show)
session_start();
if(strtolower($_GET['via']) == 'twitter'){
//login to twitter
$from = strip_tags($_GET['from']);
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
/* Get temporary credentials. */
$request_token = $connection->getRequestToken($from);
/* Save temporary credentials to session. */
$_SESSION['oauth_token'] = $token = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];
switch ($connection->http_code) {
case 200:
/* Build authorize URL and redirect user to Twitter. */
$url = $connection->getAuthorizeURL($token);
header('Location: ' . $url);
break;
default:
/* Show notification if something went wrong. */
echo 'Could not connect to Twitter. Refresh the page or try again later.';
}
}elseif(!empty($_GET['oauth_verifier']) && !empty($_SESSION['oauth_token']) && !empty($_SESSION['oauth_token_secret'])){
/* If last connection failed don't display authorization link. */
$_SESSION['oauth_verifier'] = $_GET['oauth_verifier'];
$twitteroauth = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);
// Let's request the access token
$access_token = $twitteroauth->getAccessToken($_SESSION['oauth_verifier']);
// Save it in a session var
$_SESSION['access_token'] = $access_token;
// Let's get the user's info
$user_info = $twitteroauth->get('account/verify_credentials');
$home_timeline = $twitteroauth->get('statuses/home_timeline', array('count' => 3));
// Print user's info
echo "<pre>";
print_r($user_info);
echo "</pre>";
echo "<pre>";
print_r($home_timeline);
echo "</pre>";
}
So after saving to a variable and authenticating, I then am able to query the API as expected. After I switch to a different page with essentially the same code as in the elseif() block, I simple recieve the following error message when I attempt to pull data:
stdClass Object
(
[request] => /1/account/verify_credentials.json?oauth_consumer_key=djtrixYaxkM4QFzhtfTg&oauth_nonce=8d27112c1ee645b4253c8f803cf428d4&oauth_signature=N6Ug5w%2BNqzo%2FY%2By7UuO0jDqWUdA%3D&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1297720180&oauth_token=&oauth_version=1.0
[error] => Could not authenticate you.
)
Any insight on how I can get this authentication to "stick" across the session?
EDIT
As pointed out below, in the URL oauth_token has no value. So I did a print_r($_SESSION) and I am seeing that $_SESSION['oauth_token'] does indeed have a value.
Array (
[oauth_token] => 12345
[oauth_token_secret] => 67890
[oauth_verifier] => [access_token] => Array (
[ "1.0" encoding="UTF-8"?> /oauth/access_token?oauth_consumer_key=111111
[amp;oauth_nonce] => 222222
[amp;oauth_signature] => 777777=
[amp;oauth_signature_method] => HMAC-SHA1
[amp;oauth_timestamp] => 1297783851
[amp;oauth_token] => 12345
[amp;oauth_version] => 1.0 Invalid / expired Token
)
)
This array looks like it might be malformed, but I'll freely admit I don't know what it should look like. And, as I didn't make any changes to the library - just the demo code - I'm not sure how that could have happened.
Notice that oauth_token has no value. On your other pages you are probably not initiating the session or you are not properly pulling the access token out of the session.
Try to increase OAuth oauth_timestamp by a couple of hours.
In PHP OAuth client it looks like this:
private static function generate_timestamp() {
return time()+5*3600;
}
resources
http://www.backwardcompatible.net/149-Twitter-Timestamp-out-of-bounds-solved
Related
I've got a bit of a weird issue going on with the new php-sdk and I can't seem to work it out.
I've got a phalconphp application where I present the user with the sign up view if they are not currently signed in, regardless of the url I present this view (Without redirecting the url)
When I set-up my FacebookRedirectLoginHelper I pass in the http host and the request uri, so that I can redirect the user back to the same page they intially tried to access e.g
Facebook\FacebookRedirectLoginHelper('http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
unfortunately this does not work. I always get an SDK exception telling me the redirect_uri isn't the one passed in. This is the case even if I am on the homepage e.g
var_dump($_SERVER['REQUEST_URI']);
returns "/"
However if I explicitly put the trailing slash in instead of the request_uri then it works correctly. e.g
Facebook\FacebookRedirectLoginHelper('http://'.$_SERVER['HTTP_HOST'].'/');
I've even compared the 2 generated urls (again just on the index page so the path is simply "/") and they are exactly the same. The only issue appears to be trying to dynamically generate this. I can't for the life of me work out what is going on here. It doesn't seem to be any kind of double encoding and I'm just a bit stumped as to why this wouldn't work.
At first I thought it might be something to do with PhalconPHP and the routing but this doesn't seem to be the case as even a simple example fails.
An example simple php file is below. You will obviously need to include the sdk and set-up an app
<?php
ob_start();
session_start();
$appId = 'xxxxxxxxxxxxxxxxxxxxxxxx';
$secret = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
//require all the facebook stuff
Facebook\FacebookSession::setDefaultApplication($appId,$secret);
$helper = new Facebook\FacebookRedirectLoginHelper('http://'.$_SERVER['HTTP_HOST'] .'/'); //will work
//$helper = new Facebook\FacebookRedirectLoginHelper('http://'.$_SERVER['HTTP_HOST'] .$_SERVER['REQUEST_URI']); //won't work
// see if a existing session exists
if ( isset( $_SESSION ) && isset( $_SESSION['fb_token'] ) ) {
// create new session from saved access_token
$session = new FacebookSession( $_SESSION['fb_token'] );
// validate the access_token to make sure it's still valid
try {
if ( !$session->validate() ) {
$session = null;
}
} catch ( Exception $e ) {
// catch any exceptions
$session = null;
}
}
if ( !isset( $session ) || $session === null ) {
// no session exists
try {
$session = $helper->getSessionFromRedirect();
} catch( FacebookRequestException $ex ) {
// When Facebook returns an error
// handle this better in production code
print_r( $ex );
} catch( Exception $ex ) {
// When validation fails or other local issues
// handle this better in production code
print_r( $ex );
}
}
// see if we have a session
if ( isset( $session ) ) {
// save the session
$_SESSION['fb_token'] = $session->getToken();
// create a session using saved token or the new one we generated at login
$session = new FacebookSession( $session->getToken() );
// graph api request for user data
$request = new FacebookRequest( $session, 'GET', '/me' );
$response = $request->execute();
// get response
$graphObject = $response->getGraphObject()->asArray();
// print profile data
echo '<pre>' . print_r( $graphObject, 1 ) . '</pre>';
// print logout url using session and redirect_uri (logout.php page should destroy the session)
echo 'Logout';
} else {
// show login url
echo 'Login';
}
The actual exception is :
Facebook\FacebookAuthorizationException Object ( [statusCode:Facebook\FacebookRequestException:private] => 400 [rawResponse:Facebook\FacebookRequestException:private] => {"error":{"message":"Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request","type":"OAuthException","code":100}}
[responseData:Facebook\FacebookRequestException:private] => Array ( [error] => Array ( [message] => Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request [type] => OAuthException [code] => 100 ) ) [message:protected] => Error validating verification code. Please make sure your redirect_uri is identical to the one you used in the OAuth dialog request
I've worked this out. It was stupid of me. When the login url is generated with $_SERVER['REQUEST_URI'] it obviously comes back as "/" on the second run through it is instantiated again, but this time has the returned query string in it, thus the redirected uri set in the helper class is no longer the same as the base uri. Basically I need the request uri without the querystring
so now I just use
$_SERVER['HTTP_HOST']. strtok($_SERVER['REQUEST_URI'], '?')
I've written a twitter api application using the following tutorial:
http://www.youtube.com/watch?v=GQaPt-gQVRI
How can I modify the script to generate a timeline stream that is specific to a user so that the application when run will show user's timeline stream and not mine (since i wrote the app and therefore it has my twitter credentials)
Thanks
the php application validates my twitter credentials using the following:
<?php
require 'tmhOAuth.php'; // Get it from: https://github.com/themattharris/tmhOAuth
// Use the data from http://dev.twitter.com/apps to fill out this info
// notice the slight name difference in the last two items)
$connection = new tmhOAuth(array(
'consumer_key' => 'my key',
'consumer_secret' => 'my secret',
'user_token' => 'my token', //access token
'user_secret' => 'my user secret' //access token secret
));
// set up parameters to pass
$parameters = array();
if ($_GET['count']) {
$parameters['count'] = strip_tags($_GET['count']);
}
if ($_GET['screen_name']) {
$parameters['screen_name'] = strip_tags($_GET['screen_name']);
}
if ($_GET['twitter_path']) { $twitter_path = $_GET['twitter_path']; } else {
$twitter_path = '1.1/statuses/user_timeline.json';
}
$http_code = $connection->request('GET', $connection->url($twitter_path), $parameters );
if ($http_code === 200) { // if everything's good
$response = strip_tags($connection->response['response']);
if ($_GET['callback']) { // if we ask for a jsonp callback function
echo $_GET['callback'],'(', $response,');';
} else {
echo $response;
}
} else {
echo "Error ID: ",$http_code, "<br>\n";
echo "Error: ",$connection->response['error'], "<br>\n";
So without having to pass a new username in the api call, how can i add a snippet to require the user to log in? and if i add that snippet for the user to log in, will the api automatically populate the authentication strings with the user's?
You can send a get request to the following url to get a users timeline.
https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=twitterapi&count=2
You can replace the parameters screen_name with the username you want to access, and you can replace count with the number of tweets you would like to get, count is optional and doesn't have to be included.
You can read more about statuses/user_timeline on the office twitter API site: https://dev.twitter.com/docs/api/1.1/get/statuses/user_timeline
If you wish to get a user to sign in then your best bet would be to use the twitteroauth library by abraham
Download and include in your project, then include the library and start a session.
require("twitteroauth/twitteroauth.php");
session_start();
Then create a new instance and authenticate with your app details. You can set a url to redirect to when the user authenticates. You also need to cache your tokens.
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET');
$request_token = $twitteroauth->getRequestToken('http://example.com/loggedin.php');
$_SESSION['oauth_token'] = $request_token['oauth_token'];
$_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret'];
Redirect the user to twitter to authenticate
header('Location: '.$twitteroauth->getAuthorizeURL($request_token['oauth_token']));
In the file that you set twitter to redirect to you need to re-authenticate using the tokens created. Twitter will also add a parameter to your url which you use to create a access token for that user. Now when you send GET requests to twitter, it does it on behalf of the user logged in.
require("twitteroauth/twitteroauth.php");
session_start();
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET', $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);
$user_info = $twitteroauth->get('account/verify_credentials');
print_r($user_info);
You can get additional details from $user_info which you can cache or store in a database, which will allow you to remember users that have already authenticated. You will need to use oauth_token and oauth_secret, something like this.
$twitteroauth = new TwitterOAuth('YOUR_CONSUMER_KEY', 'YOUR_CONSUMER_SECRET', 'OAUTH_TOKEN', 'OAUTH_SECRET');
I am connecting to Tumblr (it's the same process as twitter almost identical).
I get all the way through to the verify page, verify the app, then get returned to the previos page, all of the correct stuff is on the querystring but i get a 400 error a bit on the API docs says that this means "invalid input data".
Here's my code:
require("tumblr/tumblroauth/tumblroauth.php");
// Enter your Consumer / Secret Key:
$consumer = $conf['Tumblr']['consumer'];
$secret = $conf['Tumblr']['secret'];
/* Start session and load lib */
if(!isset($_REQUEST['oauth_token']))
{
// Start the Session
session_start();
$connection = new TumblrOAuth($conf['Tumblr']['consumer'], $conf['Tumblr']['secret']);
// this url is correct
$url = "http://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$temporary_credentials = $connection->getRequestToken($url);
$redirect_url = $connection->getAuthorizeURL($temporary_credentials, FALSE);
echo "going to".$redirect_url; // looks good
//have to use this as headers have started
echo '<script>window.location.href="'.$redirect_url.'";</script>';
}
/* If the oauth_token is old redirect to the connect page. */
if (isset($_REQUEST['oauth_token']) && $_SESSION['oauth_token'] !== $_REQUEST['oauth_token']) {
$_SESSION['oauth_status'] = 'oldtoken';
session_destroy();
}
if(isset($_REQUEST['oauth_token']))
{/* Create TumblroAuth object with app key/secret and token key/secret from default phase */
$connection = new TumblrOAuth($consumer, $secret, $_SESSION['oauth_token'], $_SESSION['oauth_token_secret']);
/* Request access tokens from tumblr */
$access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']);
/* Save the access tokens. Normally these would be saved in a database for future use. */
$_SESSION['access_token'] = $access_token;
/* Remove no longer needed request tokens */
unset($_SESSION['oauth_token']);
unset($_SESSION['oauth_token_secret']);
/* If HTTP response is 200 continue otherwise send to connect page to retry */
if (200 == $connection->http_code) {
/* The user has been verified and the access tokens can be saved for future use */
$_SESSION['status'] = 'verified';
echo 'connection made heres the code:<br/>'.$connection->http_code;
} else {
/* Save HTTP status for error dialog on connnect page.*/
// THIS IS ALWAYS BEING OUTPUT AT THE END
echo "oh no something is wrong code:<br/>".$connection->http_code;
}
}
Please can someone have a look I feel like I have tried everything on the planet to get this to work..
ps using : https://github.com/jacobbudin/tumblroauth
I think your problem is here
$redirect_url = $connection->getAuthorizeURL($temporary_credentials, FALSE);
Try
$redirect_url = $connection->getAuthorizeURL($temporary_credentials);
and let us know if you're still having trouble
I am using Abraham Williams twitter api in order to log in the user. During step one I store the temporary oauth_token and oauth_token _secret in the session. After the user is redirected to my page after the sign in process the session data stored previously are lost. How can I solve this ?
function oauth()
{
//Build TwitterOAuth object with client credentials
$connection = new TwitterOAuth($this->consumer_key, $this->consumer_secret);
//Get temporary credentials
$request_token = $connection->getRequestToken($this->callback);
//Save temporary credentials to session
$session_data = array(
'oauth_token' => $request_token['oauth_token'],
'oauth_token_secret'=> $request_token['oauth_token_secret'],
);
$this->session->set_userdata($session_data);
//If last connection failed don't display authorization link.
switch ($connection->http_code)
{
case 200:
$url = $connection->getAuthorizeURL($request_token['oauth_token'], TRUE);
header('Location: ' . $url);
break;
default:
echo 'Could not connect to Twitter. Refresh the page or try again later.';
}
}
function callback()//callback after user signs in with twitter
{
$connection = new TwitterOAuth($this->consumer_key,
$this->consumer_secret,
$this->session->userdata("oauth_token"),
$this->session->userdata("oauth_token_secret"));
$access_token = $connection->getAccessToken($_REQUEST['oauth_verifier']);
$this->session->set_userdata('access_token', $access_token);
//Remove no longer needed request tokens
$this->session->unset_userdata('oauth_token');
$this->session->unset_userdata('oauth_token_secret');
//If HTTP response is 200 continue otherwise send to connect page to retry
if (200 == $connection->http_code)
{
$this->session->set_userdata('twitter_log_in', TRUE);
redirect('/main/', 'refresh');
}
}
Of course you verified you config file in Session section, but:
Already you tried it in other PC?
Tried DB Sessions or the inverse?
Made you simple tests excluding you case (twitter oauth class)
In somehow, maybe the code are replacing the vars, try log the informations in many parts of the code, to see if it as overwrote in the life of the process
Im using the following code to read to consumer_key and consumer_secret from config.php, pass it to twitter and retrieve some bits of information back from them.
What the script below attempts to do is 'cache' the request_token and request_secret. So in theory I should be able to reuse those details (all 4 of them to automatically tweet when required).
<?php
require_once('twitteroauth/twitteroauth.php');
require_once('config.php');
$consumer_key = CONSUMER_KEY;
$consumer_secret = CONSUMER_SECRET;
if (isset($_GET["register"]))
{
// If the "register" parameter is set we create a new TwitterOAuth object
// and request a token
/* Build TwitterOAuth object with client credentials. */
$oauth = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET);
$request = $oauth->getRequestToken();
$request_token = $request["oauth_token"];
$request_token_secret = $request["oauth_token_secret"];
// At this I store the two request tokens somewhere.
file_put_contents("request_token", $request_token);
file_put_contents("request_token_secret", $request_token_secret);
// Generate a request link and output it
$request_link = $oauth->getAuthorizeURL($request);
echo "Request here: " . $request_link . "";
die();
}
elseif (isset($_GET["validate"]))
{
// This is the validation part. I read the stored request
// tokens.
$request_token = file_get_contents("request_token");
$request_token_secret = file_get_contents("request_token_secret");
// Initiate a new TwitterOAuth object. This time we provide them with more details:
// The request token and the request token secret
$oauth = new TwitterOAuth($consumer_key, $consumer_secret,
$request_token, $request_token_secret);
// Ask Twitter for an access token (and an access token secret)
$request = $oauth->getAccessToken();
// There we go
$access_token = $request['oauth_token'];
$access_token_secret = $request['oauth_token_secret'];
// Now store the two tokens into another file (or database or whatever):
file_put_contents("access_token", $access_token);
file_put_contents("access_token_secret", $access_token_secret);
// Great! Now we've got the access tokens stored.
// Let's verify credentials and output the username.
// Note that this time we're passing TwitterOAuth the access tokens.
$oauth = new TwitterOAuth($consumer_key, $consumer_secret,
$access_token, $access_token_secret);
// Send an API request to verify credentials
$credentials = $oauth->oAuthRequest('https://twitter.com/account/verify_credentials.xml', 'GET', array());
// Parse the result (assuming you've got simplexml installed)
$credentials = simplexml_load_string($credentials);
var_dump($credentials);
// And finaly output some text
echo "Access token saved! Authorized as #" . $credentials->screen_name;
die();
}
?>
When i run /?verify&oauth_token=0000000000000000 - It works however trying to resuse the generated tokens etc... I get a 401
Here is the last bit of code where I attempt to reuse the details from Twitter combined with my consumer_key and consumer_secret and get the 401:
require_once('twitteroauth/twitteroauth.php');
require_once('config.php');
// Read the access tokens
$access_token = file_get_contents("access_token");
$access_token_secret = file_get_contents("access_token_secret");
// Initiate a TwitterOAuth using those access tokens
$oauth = new TwitterOAuth($consumer_key, $consumer_key_secret,
$access_token, $access_token_secret);
// Post an update to Twitter via your application:
$oauth->OAuthRequest('https://twitter.com/statuses/update.xml',
array('status' => "Hey! I'm posting via #OAuth!"), 'POST');
Not sure whats going wrong, are you able to cache the details or do i need to try something else?
You can't store the OAuth tokens in cache and to more than 1 request with it, as OAuth is there to help make the system secure, your "oauth_token" will contain some unique data, this token will only be able to make one call back to twitter, as soon as the call was made, that "oauth_token" is no longer valid, and the OAuth class should request a new "oauth_token", thus making sure that every call that was made is secure.
That is why you are getting an "401 unauthorized" error on the second time as the token is no longer valid.
twitter is still using OAuth v1 (v2 is still in the draft process even though facebook and google already implemented it in some parts)
The image below describes the flow of the OAuth authentication.
Hope it helps.
A while ago I used this to connect to twitter and send tweets, just note that it did make use of some Zend classes as the project was running on a zend server.
require_once 'Zend/Service/Twitter.php';
class Twitter {
protected $_username = '<your_twitter_username>';
protected $_token = '<your_twitter_access_token>';
protected $_secret = '<your_twitter_access_token_secret>';
protected $_twitter = NULL;
//class constructor
public function __construct() {
$this->getTwitter();
}
//singleton twitter object
protected function getTwitter() {
if (null === $this->_twitter) {
$accessToken = new Zend_Oauth_Token_Access;
$accessToken->setToken($this->_token)
->setTokenSecret($this->_secret);
$this->_twitter = new Zend_Service_Twitter(array(
'username' => $this->_username,
'accessToken' => $accessToken,
));
$response = $this->_twitter->account->verifyCredentials();
if ($response->isError()) {
throw new Zend_Exception('Provided credentials for Twitter log writer are wrong');
}
}
return $this->_twitter;
}
//send a status message to twitter
public function update( $tweet ) {
$this->getTwitter()->status->update($tweet);
}
}
In your second script, it looks like you aren't setting the Consumer Key and Consumer Secret when you create your TwitterOAuth instance.
// Initiate a TwitterOAuth using those access tokens
$oauth = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token, $access_token_secret);