How I got Twitter, UNIX Timestamps, and Drupal 7 to all play nice

Recently I had an opportunity to work with Twitter module for Drupal 7 on one of the projects. Most of the functionality I needed for the project was already available within the module and with few tweaks here and there I can get the task done.

Here at Metal Toad Media we take a lot of pride in our work. We try to do everything we can in order to ensure that by the time our code gets into hands of our client, it is a solid product. There are several stages in our development cycle to aid the process of QA. Each developer has a local server running on their machine and this is where most of the magic happens. Once a feature has been implemented and thoroughly tested on the local machine, we proceed and deploy the code onto a development server. Once our code makes it onto development server, project managers (PM's) can check out our work and do some testing of their own. After PM's are done with the QA and give us the green light, we deploy this code onto a staging server where the client can assess our work and give us feedback if they want any further changes to their website.

By this point, our code has been evaluated by development team, project manager(s), client(s) and whoever they share the link to the staging website with. That is a pretty decent sample group of testers and at this point we can pass the code to the client feeling good about our work.

This is the process we use on all of our projects including this one. Social networking integration was implemented and tested, passed the project manager QA on development server, client QA on the staging server. We passed the code to the client and everyone lived happily ever after. Well, that's until the client deployed the code on their server and all of the sudden, Twitter OAuth wasn't working anymore.

Symptom

When user would try to authenticate using Twitter OAuth they would get an error due to oauth_token not being populated by the module. During failed authentication handshake user is forwarded to:

https://api.twitter.com/oauth/authenticate?oauth_token=

Troubleshooting

My first hunch was that either OAuth key pair was off or the Twitter app permissions were not set up properly. However, upon further investigation I found out that this was not the case. It was weird as no matter what I used as OAuth keys, I would get the same thing. I checked out Drupal and server logs, but nothing was reported in either of them. I cannot replicate this bug on development or staging servers and production server is not reporting anything wrong in the logs. Now I'm in a big no-no situation. I have to start messing with the code in the production environment. We talked to the client, explained what needs to be done and that there might be potential outages across the website during the troubleshooting process. I was going line by line through the Twitter module, print statement here, print there until I located point of failure.

During the authentication handshake, one of the parameters passed to Twitter API is the UNIX timestamp. This is a security measure to reduce the possibility of someone re-using the authentication token by having it expire after a certain period. Since the server time was not properly synchronized (it was behind several hours), each OAuth token was generated expired, thus the authentication failure. This seemed to be one of the expected scenarios by Twitter module developers as this call was wrapped in a try block. Except the catch block was left empty, probably an oversight.

// From twitter.lib.php - Lines 310-320 v7.x-3.1
public function get_access_token() {
  $url = $this->create_url('oauth/access_token', '');
  try {
    $response = $this->auth_request($url);
  }
  catch (TwitterException $e)  {
  }
  parse_str($response, $token);
  $this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
  return $token;
}

As a result, I have no feedback of what is failing or why it is failing and am left poking around in the production environment.

Lessons Learned

  • If you are ever in a situation where you are setting up a new server environment, make sure that server time being synchronized is on your checklist of TO-DO things. Otherwise some obvious and not so obvious, time sensitive operations will cause you headaches.
  • Always make sure that your exception catch block is implemented, and exception is properly handled. It is OK not to print this error back to the user, especially when the report might have security implications. However, at the very least, print something to the logs so you leave a trace for the developer to troubleshoot the issue.

The URL to the live website was not advertised to the public yet, so the consequences of any downtime caused by poking around in the production environment were fairly mild. But this didn't have to be the case. This could have been a website with high traffic volume, where any extended downtime translates in significant revenue loss. Debugging in production will not be an option most of the time, so do yourself and everyone else a favor: sync your clocks and handle your exceptions!

Filed under:

Ready to get started?