User Authentication with Codeigniter 1.7 using Twitter oAuth

Exclusive offer: get 50% off this eBook here
CodeIgniter 1.7 Professional Development

CodeIgniter 1.7 Professional Development — Save 50%

Become a CodeIgniter expert with professional tools, techniques and extended libraries

$23.99    $12.00
by Adam Griffiths | May 2010 | Open Source PHP Web Development

User authentication is an important part of many applications. Let's look at how we would utilize third-party authentication methods. oAuth is an open protocol for secure user authentication across APIs. It allows users to gain limited access to websites by using their Twitter credentials. It's a very sound method of user authentication, and doesn't take too much work to get going. Twitter oAuth is used by hundreds of third-party Twitter clients and mashups—just to give you an idea of how useful it can be.

In this article by Adam Griffiths, author of CodeIgniter 1.7 Professional Development, we will:

  • Learn how Twitter oAuth works
  • Create a library for authentication
  • Utilize the library in order to create an application to demonstrate how it works

(Read more interesting articles on CodeIgniter 1.7 Professional Development here.)

How oAuth works

Getting used to how Twitter oAuth works takes a little time.

When a user comes to your login page, you send a GET request to Twitter for a set of request codes. These request codes are used to verify the user on the Twitter website.

The user then goes through to Twitter to either allow or deny your application access to their account. If they allow the application access, they will be taken back to your application. The URL they get sent to will have an oAuth token appended to the end. This is used in the next step.

Back at your application, you then send another GET request for some access codes from Twitter. These access codes are used to verify that the user has come directly from Twitter, and has not tried to spoof an oAuth token in their web browser.

Registering a Twitter application

Before we write any code, we need to register an application with Twitter. This will give us the two access codes that we need. The first is a consumer key, and the second is a secret key. Both are used to identify our application, so if someone posts a message to Twitter through our application, our application name will show up alongside the user's tweet.

To register a new application with Twitter, you need to go to http://www.twitter.com/apps/new. You'll be asked for a photo for your application and other information, such as website URL, callback URL, and a description, among other things.

You must select the checkbox that reads Yes, use Twitter for login or you will not be able to authenticate any accounts with your application keys.

Once you've filled out the form, you'll be able to see your consumer key and consumer secret code. You'll need these later. Don't worry though; you'll be able to get to these at any time so there's no need to save them to your hard drive. Here's a screenshot of my application:

Downloading the oAuth library

Before we get to write any of our CodeIgniter wrapper library, we need to download the oAuth PHP library. This allows us to use the oAuth protocol without writing the code from scratch ourselves.

You can find the PHP Library on the oAuth website at www.oauth.net/code. Scroll down to PHP and click on the link to download the basic PHP Library; or just visit: http://oauth.googlecode.com/svn/code/php/—the file you need is named OAuth.php.

Download this file and save it in the folder system/application/libraries/twitter/—you'll need to create the twitter folder. We're simply going to create a folder for each different protocol so that we can easily distinguish between them.

Once you've done that, we'll create our Library file. Create a new file in the system/application/libraries/ folder, called Twitter_oauth.php. This is the file that will contain functions to obtain both request and access tokens from Twitter, and verify the user credentials.

The next section of the article will go through the process of creating this library alongside the Controller implementation; this is because the whole process requires work on both the front-end and the back-end. Bear with me, as it could get a little confusing, especially when trying to implement a brand new type of system such as Twitter oAuth.

Library base class

Let's break things down into small sections. The following code is a version of the base class with all its guts pulled out. It simply loads the oAuth library and sets up a set of variables for us to store certain information in. Below this, I'll go over what each of the variables are there for.

<?php
require_once(APPPATH . 'libraries/twitter/OAuth.php');
class Twitter_oauth
{
var $consumer;
var $token;
var $method;
var $http_status;
var $last_api_call;
}
?>

The first variable you'll see is $consumer—it is used to store the credentials for our application keys and the user tokens as and when we get them.

The second variable you see on the list is $token—this is used to store the user credentials. A new instance of the oAuth class OAuthConsumer is created and stored in this variable.

Thirdly, you'll see the variable $method—this is used to store the oAuth Signature Method (the way we sign our oAuth calls).

Finally, the last two variables, $http_status and $last_api_call, are used to store the last HTTP Status Code and the URL of the last API call, respectively. These two variables are used solely for debugging purposes.

Controller base class

The Controller is the main area where we'll be working, so it is crucial that we design the best way to use it so that we don't have to repeat our code. Therefore, we're going to have our consumer key and consumer secret key in the Controller. Take a look at the Base of our class to get a better idea of what I mean.

<?php
session_start();
class Twitter extends Controller
{
var $data;
function Twitter()
{
parent::Controller();
$this->data['consumer_key'] = "";
$this->data['consumer_secret'] = "";
}

The global variable $data will be used to store our consumer key and consumer secret. These must not be left empty and will be provided to you by Twitter when creating your application. We use these when instantiating the Library class, which is why we need it available throughout the Controller instead of just in one function.

We also allow for sessions to be used in the Controller, as we want to temporarily store some of the data that we get from Twitter in a session. We could use the CodeIgniter Session Library, but it doesn't offer us as much flexibility as native PHP sessions; this is because with native sessions we don't need to rely on cookies and a database, so we'll stick with the native sessions for this Controller.

CodeIgniter 1.7 Professional Development Become a CodeIgniter expert with professional tools, techniques and extended libraries
Published: April 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

(Read more interesting articles on CodeIgniter 1.7 Professional Development here.)

Library constructor

The Library constructor needs to know if we have an authenticated user or not. So here's what we do. Firstly, we set up a new instance of the oAuth Consumer class, creating our application details. Then we check to see if oAuth tokens have been passed to the function. If they have, it means that the user has returned from Twitter; if not, they have just come onto the site and are ready to click on the link to authenticate themselves. We pass the data to the function as an array, as this is the only way that CodeIgniter lets us do this with the $this->load->library function.

function Twitter_oauth($data)
{
$this->method = new OAuthSignatureMethod_HMAC_SHA1();
$this->consumer = new OAuthConsumer($data['consumer_key'],
$data['consumer_secret']);
if(!empty($data['oauth_token'])
&& !empty($data['oauth_token_secret']))
{
$this->token = new OAuthConsumer($data['oauth_token'],
$data['oauth_token_secret']);
}
else
{
$this->token = NULL;
}
}

Requesting user tokens

The first thing that we need to do to authenticate a user is to query Twitter for request tokens. These tokens are used to authenticate a user to let Twitter know that they came from our application. Let's take a look at the function for requesting tokens:

function get_request_token()
{
$args = array();
$request = OAuthRequest::
from_consumer_and_token($this->consumer, $this->token,
'GET', "https://twitter.com/oauth/request_token", $args);
$request->sign_request($this->method, $this->consumer, $this->token);
$request = $this->http($request->to_url());

$token = $this->parse_request($request);

$this->token = new OAuthConsumer($token['oauth_token'],
$token['oauth_token_secret']);

return $token;
}

As you can see here, we are using the OAuthRequest class provided by us in the PHP library that we downloaded earlier, to set up a new request to Twitter. Next, we have to sign our request; this is so that we can encrypt data between our own application and Twitter. The final thing that we do to complete the request is to use a function called http() to go ahead and pull the data from Twitter.

Once this is all done, we pass the array to the function parse_request()—this simply parses all of the data for this request, and gives it back to us in an associative array.

Finally, after all of that is complete, we can create a new instance of the OAuthConsumer class, with the new tokens from Twitter. Then we simply return the tokens from the function in a variable.

HTTP function

Because this is quite a large dependant to the previous function, we'll go through building it here. This function is slightly more complex than the others. We use cURL to initiate the request to Twitter and to return all values from Twitter. If you already have some cURL knowledge, then you can skip the explanation after the next code block.

function http($url, $post_data = null)
{
$ch = curl_init();

if(defined("CURL_CA_BUNDLE_PATH"))
curl_setopt($ch, CURLOPT_CAINFO, CURL_CA_BUNDLE_PATH);

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

if(isset($post_data))
{
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}

$response = curl_exec($ch);
$this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$this->last_api_call = $url;
curl_close($ch);

return $response;
}

The first thing that we need to do to use cURL is run the curl_init() function. This will return a cURL handle to a function. All subsequent functions must pass this handle as their first parameter.

Observe the following code:

if(defined("CURL_CA_BUNDLE_PATH"))
curl_setopt($ch, CURLOPT_CAINFO, CURL_CA_BUNDLE_PATH);

This allows us to validate the SSL certificate to make sure that the peer's SSL certificate is valid. In short we setup cURL to check if Twitter's SSL certificate is valid.

The next few lines of code set up the connection to the URL and set some conditions for the connection, such as the timeout, and set the SSL verifier to false.

Next up, we check to see if the variable $post_data has already been set. This will set the data that we would like to send to Twitter if we make a POST request. This is setting up the Library so we can send status messages to Twitter if we wanted to.

Finally, we get to the part of the code that performs the operation:

$response = curl_exec($ch);
$this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$this->last_api_call = $url;
curl_close($ch);

The first line shown here executes our cURL session. This will return the result on success, or false upon failure. The next two lines simply save some details for debugging purposes, and then on the last line we close the cURL session.

The very last line of this function returns the $response variable, which contains the data from the request.

Parse function

The next dependant function we have is the one that parses the response from Twitter into an array that we can actually use.

Observe the following function:

function parse_request($string)
{
$args = explode("&", $string);
$args[] = explode("=", $args['0']);
$args[] = explode("=", $args['1']);

$token[$args['2']['0']] = $args['2']['1'];
$token[$args['3']['0']] = $args['3']['1'];

return $token;
}

This function takes a string and splits it up at every occurrence of an ampersand (&). This splits it up into an array with two key value pairs. Then we split those two pairs at the equals (=) sign. Then we simply format them so that instead of the array keys being numbers, they are oauth_token and oauth_token_secret—the two items that we parse in the function.

Controller index function

As all Controllers have a default function called index, this is where we will start our code. The index function will get request tokens from Twitter and then build a URL from that. The URL will go to Twitter with one of the tokens attached, so that Twitter knows the user has come from our application. We'll save these tokens in a session so that we can verify the user when they come back to our application from Twitter.

function index()
{
$this->load->library('twitter_oauth', $this->data);

$token = $this->twitter_oauth->get_request_token();

$_SESSION['oauth_request_token'] = $token['oauth_token'];
$_SESSION['oauth_request_token_secret'] =
$token['oauth_token_secret'];

$request_link = $this->twitter_oauth->get_authorize_URL($token);

$data['link'] = $request_link;
$this->load->view('twitter/home', $data);
}

As you can see here, the first thing that we do is load the Twitter oAuth library and pass the global variables to it—our consumer key and consumer secret. The next thing that we do is get the request tokens from Twitter and then save these to a session. The next line is where we build the request link, so that when we link people to Twitter they'll be recognized correctly. This uses a function get_authorize_url(), which we'll build in the next section. Then we put this link into an array so that we can easily pass it to the view file.

get_authorize_URL function

This function takes the token passed to it and appends it to a Twitter URL. It's fairly straightforward.

function get_authorize_URL($token)
{
if(is_array($token)) $token = $token['oauth_token'];
return "https://twitter.com/oauth/authorize?oauth_token=" . $token;
}

Main view file

We need to create a folder for our Twitter-related view files. Go ahead and create a folder inside the system/application/views/ folder, called twitter. This is simply to make everything easily maintainable. When that's done, create a new file called home.php and, enter the code given next.

This is a simple HTML page that just echoes out the URL to Twitter so that users can easily be authorized. You'll notice the only element on the page is the link to Twitter. Right now we don't need to include anything else.

<!DOCTYPE HTML>
<html>
<head>
<title>Twitter oAuth</title>
</head>
<body>

<p>
<a href="<?php echo $link; ?>">
Click here to login with Twitter oAuth</a>
</p>

</body>
</html>

This is simply a link. In a browser, it should appear similar to the example shown in the next screenshot:

Change your callback URL

Once a user comes back to your application, you can verify their new access tokens with Twitter to ensure that they have come from Twitter and are not trying to spoof tokens to gain unauthorized access to your application. For this, we need to change our callback URL slightly.

We'll be creating a function in our Twitter Controller that will handle all of this; it will be called access()—this is where you need to change your callback URL. It should look something like this:

http://www.example.com/index.php/twitter/access/

That way, when a user comes back to your application, they will be in the right place for you do to the rest of the legwork.

Creating the access function

The access function does a few things that are crucial to authenticating users correctly. Firstly, we set the tokens that we saved in the sessions and pass them to the library in order to create a new instance of the oAuth Consumer class, but this time as the user who is using the users tokens. Next, we query Twitter for access tokens. These are the tokens that verify that the user has come from Twitter and that we can authenticate them. Once that is done, we save the new tokens and then display another view file. The view file simply tells you to take a look at your connections page on Twitter to check if your application is on there.

function access()
{
$this->data['oauth_token'] = $_SESSION['oauth_request_token'];
$this->data['oauth_token_secret'] =
$_SESSION['oauth_request_token_secret'];

$this->load->library('twitter_oauth', $this->data);

$tokens = $this->twitter_oauth->get_access_token();

$_SESSION['oauth_access_token'] = $tokens['oauth_token'];
$_SESSION['oauth_access_token_secret'] =
$tokens['oauth_token_secret'];

$this->load->view('twitter/accessed', $tokens);
}

The view file

The view file that we use for this is very simple. We passed the $tokens variable to the view file; this lets us echo the user's screen name in the title of the page.

<!DOCTYPE HTML>
<html>
<head>
<title>Twitter oAuth - @<?php echo $screen_name; ?></title>
</head>
<body>

<p>Your account should now be registered with Twitter. Check here:
<a href="https://twitter.com/account/connections">
https://twitter.com/account/connections
</a>
</p>

</body>
</html>

The page should appear similar to the example shown in the next screenshot:

CodeIgniter 1.7 Professional Development Become a CodeIgniter expert with professional tools, techniques and extended libraries
Published: April 2010
eBook Price: $23.99
Book Price: $39.99
See more
Select your format and quantity:

(Read more interesting articles on CodeIgniter 1.7 Professional Development here.)

Getting access tokens

Getting the access tokens from Twitter takes two new functions. Firstly, there is the function get_access_tokens(), which is almost identical to the get_request_tokens() function. Then there is a new function called parse_access()—this is very much like the parse_request() function, although it works slightly differently.

get_access_tokens()

This function works in almost exactly the same way as the get_request_tokens() function. It just queries a different URL and uses a different parsing function.

function get_access_token()
{
$args = array();

$request = OAuthRequest::
from_consumer_and_token($this->consumer, $this->token, 'GET',
"https://twitter.com/oauth/access_token", $args);
$request->
sign_request($this->method, $this->consumer, $this->token);
$request = $this->http($request->to_url());

$token = $this->parse_access($request);

$this->token = new OAuthConsumer($token['oauth_token'],
$token['oauth_token_secret']);

return $token;
}

parse_access()

This function takes the string returned from Twitter and splits it up at each & and =, splitting them into pairs of array keys and values. The function then returns the array for use in the class.

Logging out

When you log users out of your application, you need to destroy all session data. This is so that you can easily create a new session for them if they wish to log in again with a clean slate. Here's the function to do this.

This should go in your Controller code so that you can access it from the URI index.php/twitter/logout/.

function logout()
{
session_destroy();

$this->load->view('twitter/logout');
}

The view file for this page is fairly simple. Create a new file inside your Twitter views folder called logout.php.

<!DOCTYPE HTML>
<html>
<head>
<title>Twitter oAuth - Logged Out</title>
</head>
<body>
<p>You are no longer logged in!</p>
</body>
</html>

Debug function

We should add in a debug function for ease of use. When the debug function is called, we want to echo out the URL of the last API call, and the HTTP Status Code. Here's how we do that:

function debug_info()
{
echo("Last API Call: ".$this->last_api_call."<br />\n");
echo("Response Code: ".$this->http_status."<br />\n");
}

Final library code

Here is the final library code, in context:

<?php

require_once(APPPATH . 'libraries/twitter/OAuth.php');

class Twitter_oauth
{
var $consumer;
var $token;
var $method;
var $http_status;
var $last_api_call;

function Twitter_oauth($data)
{
$this->method = new OAuthSignatureMethod_HMAC_SHA1();
$this->consumer = new OAuthConsumer($data['consumer_key'],
$data['consumer_secret']);
if(!empty($data['oauth_token'])
&& !empty($data['oauth_token_secret']))
{
$this->token = new OAuthConsumer($data['oauth_token'],
$data['oauth_token_secret']);
}
else
{
$this->token = NULL;
}
}

function debug_info()
{
echo("Last API Call: ".$this->last_api_call."<br />\n");
echo("Response Code: ".$this->http_status."<br />\n");
}

function get_request_token()
{
$args = array();

$request = OAuthRequest::from_consumer_and_token($this->consumer,
$this->token, 'GET',
"https://twitter.com/oauth/request_token", $args);
$request->sign_request($this->method, $this->consumer,
$this->token);
$request = $this->http($request->to_url());

$token = $this->parse_request($request);

$this->token = new OAuthConsumer($token['oauth_token'],
$token['oauth_token_secret']);

return $token;
}

function get_access_token()
{
$args = array();
$request = OAuthRequest::from_consumer_and_token($this->consumer,
$this->token, 'GET', "https://twitter.com/oauth/access_token",
$args);
$request->sign_request($this->method, $this->consumer,
$this->token);
$request = $this->http($request->to_url());

$token = $this->parse_access($request);

$this->token = new OAuthConsumer($token['oauth_token'],
$token['oauth_token_secret']);

return $token;
}

function parse_request($string)
{
$args = explode("&", $string);
$args[] = explode("=", $args['0']);
$args[] = explode("=", $args['1']);

$token[$args['2']['0']] = $args['2']['1'];
$token[$args['3']['0']] = $args['3']['1'];

return $token;
}

function parse_access($string)
{
$r = array();

foreach(explode('&', $string) as $param)
{
$pair = explode('=', $param, 2);
if(count($pair) != 2) continue;
$r[urldecode($pair[0])] = urldecode($pair[1]);
}
return $r;
}

function get_authorize_URL($token)
{
if(is_array($token)) $token = $token['oauth_token'];
return "https://twitter.com/oauth/authorize?oauth_token=" .
$token;
}

function http($url, $post_data = null)
{
$ch = curl_init();

if(defined("CURL_CA_BUNDLE_PATH"))
curl_setopt($ch, CURLOPT_CAINFO, CURL_CA_BUNDLE_PATH);

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

if(isset($post_data))
{
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}

$response = curl_exec($ch);
$this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$this->last_api_call = $url;
curl_close($ch);

return $response;
}
}
?>

Final controller code

Here is the final Controller code, in context:

<?php
session_start();

class Twitter extends Controller
{
var $data;

function Twitter()
{
parent::Controller();

$this->data['consumer_key'] = "";
$this->data['consumer_secret'] = "";
}

function index()
{
$this->load->library('twitter_oauth', $this->data);

$token = $this->twitter_oauth->get_request_token();

$_SESSION['oauth_request_token'] = $token['oauth_token'];
$_SESSION['oauth_request_token_secret'] =
$token['oauth_token_secret'];

$request_link = $this->twitter_oauth->get_authorize_URL($token);

$data['link'] = $request_link;
$this->load->view('twitter/home', $data);
}

function access()
{
$this->data['oauth_token'] = $_SESSION['oauth_request_token'];
$this->data['oauth_token_secret'] =
$_SESSION['oauth_request_token_secret'];
$this->load->library('twitter_oauth', $this->data);

/* Request access tokens from twitter */
$tokens = $this->twitter_oauth->get_access_token();
/*Save the access tokens.*/
/*Normally these would be saved in a database for future use. */
$_SESSION['oauth_access_token'] = $tokens['oauth_token'];
$_SESSION['oauth_access_token_secret'] =
$tokens['oauth_token_secret'];

$this->load->view('twitter/accessed', $tokens);
}

function logout()
{
session_destroy();
$this->load->view('twitter/logout');
}
}
?>

Summary

There you have it—user authentication using Twitter oAuth. In the next article we will cover User Authentication with Codeigniter 1.7 using Facebook Connect. There are many similarities in how these systems work, but for us developers they both work slightly differently; Twitter makes us jump through hoops, and Facebook handles it all for us.


If you have read this article you may be interested to view:


About the Author :


Adam Griffiths

Adam Griffiths is a student and freelance CodeIgniter Developer based in the United Kingdom. He has five years web development experience, the last two being largely influenced by CodeIgniter. He has worked on many websites, both large and small, from small blogs to large multi-national companies. He is well versed in development techniques and how to squeeze that little bit more from an application. He has also made a number of contributions to the CodeIgniter Community, most notably The Authentication Library, a very simple-to-use but full-featured Authentication Library for CodeIgniter.

When CodeIgniter and PHP aren't spiralling around his head, Adam enjoys practising card and mentalist tricks, mainly sleight of hand and card handling. He has performed at local and formal functions for hundreds of people. He is also a guitar player and enjoys playing acoustically at pubs and small gigs. Moving back towards computing, he has a deep interest in Cryptography. He loves finding patterns in data and loves using pen and paper to decipher any cipher text he may find around the web.

Books From Packt


jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

MooTools 1.2 Beginner's Guide
MooTools 1.2 Beginner's Guide

Plone 3 Products Development Cookbook
Plone 3 Products Development Cookbook

Magento 1.3: PHP Developer's Guide
Magento 1.3: PHP Developer's Guide

Spring Python 1.1
Spring Python 1.1

NetBeans Platform 6.9 Developer's Guide
NetBeans Platform 6.9 Developer's Guide

NHibernate 2 Beginner's Guide
NHibernate 2 Beginner's Guide

Agile Web Application Development with Yii1.1 and PHP5
Agile Web Application Development with Yii1.1 and PHP5


Your rating: None Average: 4 (3 votes)
Undefined variables by
After authenticating with Twitter, I'm getting "Undefined index: oauth_request_token" and "Undefined index: oauth_request_token_secret" It seems that the session variables aren't being saved.
Codes and file listing by
Codes and file listing here
Not just authentication by
Can I use this lib to get data from twitter and set data to twitter? Can you explain it?
Not just authentication by
Can I use this lib to retrieve or set data to twitter? I yes, can you explain how to
Abhi by
Thanks for the great tutorial but I am confused about where to save these php and html code. You haven't mention many filenames and their location too like the controller code and other HTML code. Would be happy if you can help me out. Thanks again

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
a
4
d
3
z
v
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software