Creating a Twitter OAuth Application

OAuth can be a tricky concept to wrap your head around at first, but with the Twitter API now requiring its use, it is something you need to understand before creating a Twitter application. This tutorial will introduce you to OAuth, and walk you through the process of creating a basic application.


Introduction

In this tutorial, we will be building a simple app that allows users to apply different effects to their Twitter avatar. In order to work with the Twitter API, we must use OAuth to authorize our app to make requests on the user's behalf.

Our application flow will be something like this:

  1. The user is asked to connect with Twitter.
  2. The user is presented a list of preview avatars to select from.
  3. Upon selection, the user is presented a confirmation screen showing the original and new avatar for comparison. The user is also offered an option to send a tweet.
  4. After the user confirms, the app creates and uploads the modified avatar to Twitter and a success page is displayed.

Setup

To start, we should set up our source directory. We need a lib directory for our PHP library (class) files, a tmp directory to keep temporary files (this needs to writable by the server), a css directory for our style sheet, and an img directory for any images.

Here's what your directory tree should look like:

  • tutorial
    • css
    • img
    • lib
    • tmp (writable)

Register Your Application

In order to use OAuth, you'll need what is called a consumer key and secret to identify your app. To obtain these, you must register an application with Twitter by following these steps.

Go to the registration page, logging in if necessary. You'll be greeted by the form pictured below:

Fill out the form with details pertaining to your app. In our case, the Application Type is Browser and we need to set a default Callback URL. This URL can be anything as long as it is a valid format. We will be overriding the callback within our code, so it isn't critical that it is a real URL. The Default Access type should be Read & Write for convenience.

Once you register and accept the terms, you'll be presented with information on your new application. The important details we need are the Consumer key and Consumer secret, which should look something like this:


Download the tmhOAuth Library

We will be making use of a library to handle all the details behind making OAuth requests. In this tutorial, we will be using @themattharris' tmhOAuth library, which supports file uploading.

  1. Download tmhOAuth from GitHub
  2. Extract tmhOAuth.php to the lib directory we created earlier

Authentication

Authentication with OAuth is basically a three step process. For a more in depth explanation, see this page on authentication at Twitter, but here is a summary:

  1. App obtains a request token: The first step is for our app to identify itself to Twitter (using its consumer key) and obtain a request token. We'll need to save this request token for later.
  2. User authorizes app on Twitter: The user now needs to be sent to Twitter in order to grant our app access to their account. After that, the user is sent back to the callback URL specified by the app.
  3. App exchanges request token for access token: Now that our app has been approved, it can exchange the request token from step 1 for an access token. Once we have the access token, our app is free to interact with the Twitter API on the user's behalf.

So let's get started with some code. We'll handle all authentication tasks in a class called TwitterApp. Start with the following code in a new file called lib/TwitterApp.php:

Here we've created three properties and a simple constructor. The $tmhOAuth property will be a tmhOAuth object, which will be used throughout the class. The $userdata property will hold an object containing info on the user such as their Twitter user name and status. The $state property keeps track of the current state of authentication.

The constructor simply accepts a tmhOAuth object and assigns it to the $tmhOAuth property.


Step 1: Get a Request Token

Here is the method to obtain a request token:

To understand the first part, you need to know about the tmhOAuth::request() method. This method allows us to make an OAuth enabled HTTP request, and it has the following usage:

tmhOAuth::request($method, $url[, $params[, $useauth[, $multipart]]])

  • string $method - The request method to use (GET, POST, etc.)
  • string $url - The URL to access
  • array $params (optional) - Associative array of parameters to include in the request
  • bool $useauth (optional, default true) - Is authentication required?
  • bool $multipart (optional, default false) - Set to true for file uploads

For the $url parameter, we make use of the tmhOAuth::url() method to craft a URL based on the API method we are calling:

tmhOAuth::url($request[, $format])

  • string $request - The api method (without extension)
  • string $format (optional, default 'json") - The desired response format (JSON, XML, etc.)

Now that you are familiar with those methods, we must make a POST request to the oauth/request_token API method. This will return OAuth data in a special format, so we need to set the format to blank when we use the tmhOAuth::url() method. We also need to pass a variable called oauth_callback, which is where the user will return after authorizing at Twitter. We will use the tmhOAuth::php_self() method to refer to the current page. Here is that code again:

Once we make the request, the response is stored as an array in the tmhOAuth::response property, with the following key pieces of data:

  • code - The HTTP response code
  • response - The actual data returned
  • headers - The response headers

So the next part of our code checks the response code (200 means success), and then places the oauth_token and oauth_token_secret that we received into session variables since we'll need them later. These are extracted from the response data using the tmhOAuth::extract_params() method, which returns an array of data contained in the response. We also set an authstate session variable to signal that we are on the next stage of authentication. Here is the code:

After that is done, we must now redirect the user to the oauth/authorize URL, including the oauth_token in a GET parameter. Here is that code again:


Step 2: Get an Access Token

Here is the method to exchange our request token for an access token:

The first thing we do is set the user_token and user_secret in the tmhOAuth::config array to the request token we obtained earlier.

The next part is where we make a POST request to oauth/access_token. We pass the oauth_verifier we received in a GET variable as a parameter in this request.

Twitter will respond with an access token and secret, which we'll need to save for any future requests. So the next chunk of code takes these and saves each in a cookie, then sets the state to 2.

The redirect at the end is there to clear the URL parameters left by Twitter, and allows the cookies to take effect.


Step 3: Verify the Access Token

With our access token obtained, we should check to make sure it is valid. Here is the method to do that:

This code should look pretty familiar by now. All we do here is set the user_token and user_secret and make a GET request to 1/account/verify_credentials. If Twitter responds with a 200 code, then the access token is valid.

Another detail to note is that this is where we populate the $userdata property with the data returned by this Twitter request. The data is in the JSON format, so we use json_decode() to convert it to a PHP object. Here's that line again:


Step 4: Tie Everything Together

With our OAuth components in place, it is time to tie everything together. We need a public facing method to allow our client code to start the authentication process, and here it is:

Most of the auth() method should be self-explanatory. Based on the state, it executes the appropriate method for that stage of authentication. If the state is 1, an oauth_verifier GET variable should exists, so the method also checks that.

We should now create a public method to find out if we are authenticated. This isAuthed() method returns true if the state is 2:

We can also use a method to remove the user's authentication. This endSession() method sets the state to 0 and removes the cookies containing the access token:


Initialization

Now we need to add some things to our __construct() method to figure out which authentication state the application is in upon initialization. Also, since our code uses session variables, we should make sure the session is started with this code:

This next part is where we determine the state. State starts at 0; if there are cookies set containing an access token, state is assumed to be 2; failing that, the state is set to the authstate session variable if it exists. Here is the code:

If the state is 1, that means we are in the process of authentication. So we can go ahead and continue the process at this point:

If the state is 2, we should verify the access token. If authentication fails, this code clears the cookies and resets the state:

Here is the new constructor with these changes made:


Sending a Tweet

Now that all the authorization code is complete, we can add some common functionality to our class. Here is a method to send a tweet through the Twitter API:

The sendTweet() method accepts a string, limits it to 140 characters, and then sends it in a POST request to 1/statuses/update. This pattern should be pretty familiar by now.


The Complete TwitterApp Class


Our Application

Now that we have a class that handles all the OAuth tasks, we can now extend it with functionality specific to our application. This includes the ability to get, alter, and set the user's avatar.

We will be extending the TwitterApp class with a TwitterAvatars class. Start with the following code in a new file called lib/TwitterAvatars.php:

As you can see, the extended class includes a $path property to point to where temporary image files will go, a $filters property holding an array of image filters, and an extended constructor with a parameter to set the path. Since we are overriding the original constructor, we have to explicitly call the parent's constructor with parent::__construct().

Now we can start adding our methods.


Downloading

Obviously, we'll need the ability to download images in order to manipulate them. Here is a generic download() method that accepts a URL and returns the data at that location. The method makes a basic cURL request.


Finding URLs

Now that we can download files, we need to find the location of the files we need. There are two different images we are interested in, the standard sized thumbnail and the original full-sized image. So, we'll create a method to get each URL.

To get the standard sized thumbnail, we'll call the users/profile_image/:screen_name API method which responds with a 302 redirect to the specified user's avatar image. This means the URL will be found in the Location header. Here is that method:

Note that we are making a GET request with tmhOAuth, passing screen_name and size parameters, then returning the contents of the Location header.

There is no API method to get the full sized image, so for our next method we'll cheat a little and edit the URL. The user data contains a profile_image_url field that points to something like avatar_normal.jpg, and the original image can be found at avatar.jpg without the suffix. So this method gets the URL, removes the size suffix and returns the modified URL:


Reading Images

Now that we can locate and download images, we need a way to read them. We'll be using the GD library to manipulate images, so this method will convert the raw image data into a GD image resource.

To describe what's happening above:

  1. The image data is converted to a GD resource using the imagecreatefromstring() function.
  2. The image dimensions are recorded using imagesx() and imagesy().
  3. A new blank true color image with the same dimensions is created using imagecreatetruecolor().
  4. The original image is copied into the new image using the imagecopy() function. This results in a true color version of the original image regardless of the original color mode.
  5. The original image resource is destroyed using imagedestroy() and the handle to the new image is returned.

Saving Images

Now that we can download images and create a GD resource, we need a method to save the images to the file system. Here is the method that saves the supplied image as a PNG file with the specified name using imagepng():


Generating Previews

Now that we have all the pieces that power our app, we can start putting them together. In our application flow, we will give the user a selection of previews to choose from. Here is the method to generate these previews:

The first thing we do is check that the user is authenticated and then grab the user name to use later in file names.

Then we download the user's image using the getImageURL() and download() methods we have created. This data will be used repeatedly for each preview so we save it in the $data variable.

Next, we save an unmodified copy with the _orig suffix. This is for visual comparison later.

The last part of the method is where we loop through the image filters listed in the $filters property, generating an image for each filter. In each iteration, we're creating an image and applying the imagefilter() function, which accepts one of the constants we have listed in the $filters array. Then for each image we save, we add its path to an associative array (using the filter name as the key) which this method returns at the end.

The next part of our application flow asks the user to confirm their choice, so we need a way to find a specific preview. Here is the simple method to get the path to an image based on the option passed as a parameter, defaulting to the original image:


Changing The Avatar

The final stage of our application flow is to actually change the user's avatar. First we need a method to get the full sized image and apply a specific filter to it. Here it is:

That should be easy to follow since it is very similar to the generatePreviews() method. It accepts a parameter to specify an image filter and checks that it exists. Then it downloads the original image and applies the filter to it, passing back the path to the generated image as the return value.

Now we need the method that actually sends the generated image to Twitter, updating the user's avatar. This method calls the processImage() method to create the image and uploads it to Twitter via the 1/account/update_profile_image API method:

The tricky part here is the actual tmhOAuth POST request, which is a multipart request containing the raw image data. In order to do this, we must set the last parameter of the tmhOAuth::request() method to true, and pass the image variable in a special format:

@[path_to_image];type=[mime_type];filename=[file_name]

For example, if we want to upload tmp/username_grayscale_full.png, the value would be @tmp/username_grayscale_full.png;type=image/png;filename=username_grayscale_full.png.

Here is that part of the code again:


Cleaning Up

A side effect of all this file manipulation is a lot of temporary files being left behind. Here is a method to clean up the temporary directory:

This simply loops through the PNG files, deleting those more than 12 hours old. It also checks how long it has been since we checked using the timestamp on a .last_check file, allowing us to limit the check to one per hour. This way we can call this method on every request without wasting resources.

Note: We are making use of the glob() function in PHP, which is an easy way to get an array of files matching a pattern.


The Complete TwitterAvatars Class


The Front End

We have all the application's components together, so now all we need is the user interface. All the code here will go into the index.php file in the root directory. We'll start by including the libraries and setting the configuration:

Note: Be sure to replace the CONSUMER_KEY and CONSUMER_SECRET with your own.

We're going to place our code in a try-catch block so we can gracefully handle any errors, assigning their message to an $error variable.

Within the try block we can begin writing our code, starting by initializing a TwitterAvatars object called $ta with a configured tmhOAuth object:

We can clear out any old temporary files at this point:

Next we check if the user is authenticated or, failing that, if the user has requested authentication, in which case we start the process by calling the auth() method:

If the user is authenticated, we need to check if an option has been selected, otherwise we will generate previews:

If an option was selected, we need to get the paths to the old and new images for display:

Finally, we check if the user has confirmed their choice and apply the change. We also send a tweet if requested and set a $success variable to true:

Here is what we have so far:


The HTML

After the PHP code we will output the appropriate HTML, starting with this template, which sets the title and main heading:

Here's where we display a form with image inputs for each preview:

Here is the success page:

Here is the confirmation page, where we show the comparison and offer the chance to cancel:

Note that the confirmation form includes the selected filter in a hidden field.

If there is an error, we show this:

The default display is the "Connect to Twitter" button as an image input (download one of the images from the bottom of this page to the img directory):

Here's the complete HTML section:


The CSS

Here is some basic CSS to make the interface look nice, saved in css/style.css:


Results

Here is a video which details how our completed application should look:


Conclusion

If you've followed this tutorial all the way through, you should have a pretty good understanding of OAuth and what it takes to create a simple Twitter web application. Using the Twitter API is easy once you understand the basic concepts - especially if you use a library like tmhOAuth to handle the minor details.

The simple example we created in this tutorial can easily be modified or extended to do anything. So if you have a great idea for a cool new Twitter app, feel free to use this as the foundation.

Thanks for reading. If you have any questions or comments about this tutorial, please post!

Tags:

Comments

Related Articles