Secure Your Drupal 3rd Party Integrations Using OAuth

While I was researching how to integrate a Twitter application into a Drupal site I found that there was very little documentation on how to accomplish this using their OAuth protocol. This can be a pretty confusing topic, and chances are that if youʼve landed here then youʼre already somewhat familiar with what OAuth is are having the same problem that I had. The basic idea is that users can grant access to their 3rd party account, like Twitter, all without trading or saving any of the users login information. This is much more secure because the information used to communicate with the 3rd party is specific to your application and canʼt be reused by anyone else(ie: It canʼt be easily hijacked).

This post will demonstrate how to implement OAuth into your website/modules using Twitter as an example. Keep in mind, OAuth technology is not necessarily specific to Twitter, it is simply the authentication protocol they use and can also be seen used in some other 3rd party integrations, the idea is all the same.

Requirements:

Youʼll want to activate both the twitter and oauth modules. Start by creating a new module called twitter_login, make sure you specify twitter and oauth_common as dependencies in your twitter_login.info file, it should look something like this:

[php]name = Twitter Login Application
core = "6.x"
project = "twitter_app"
description = Provide a method of allowing users to register/login through
Twitter OAuth.
package = "Twitter"
dependencies[] = oauth_common
dependencies[] = twitter[/php]

Now create a new application over at dev.twitter.com, the fields donʼt really matter very much, you will need the consumer key and secret after youʼve saved the application.

After having created your Twitter application make sure you define the consumer key and consumer secret at the top of your twitter_login.module. Youʼll also want to include the Twitter API files from the twitter module.

[php]define(‘TWITTER_LOGIN_CONSUMER_KEY’, ‘consumer key goes here’); define(‘TWITTER_LOGIN_CONSUMER_SECRET’, ‘consumer secret goes here’);
define(‘TWITTER_LOGIN_API_URL’, ‘http://api.twitter.com’);
define(‘TWITTER_LOGIN_SIG_METHOD’, ‘HMAC-SHA1’);
module_load_include(‘lib.php’, ‘twitter’, ‘twitter’);
module_load_include(‘inc’, ‘twitter’, ‘twitter’);[/php]

Save the OAuth consumer data to the database using hook_init.

[php]
function twitter_login_init(){
$consumer = DrupalOAuthConsumer::load(TWITTER_LOGIN_CONSUMER_KEY, FALSE);
if ($consumer) {
$consumer->secret = TWITTER_LOGIN_CONSUMER_KEY;
$consumer->configuration[‘provider_url’] = TWITTER_LOGIN_API_URL; $consumer->configuration[‘signature_method’] = TWITTER_LOGIN_SIG_METHOD; $consumer->configuration[‘authentication_realm’] = ”;
$consumer->configuration[‘access_endpoint’] = ‘/oauth/access_token’;
$consumer->write(TRUE);
} else {
$consumer = new DrupalOAuthConsumer(TWITTER_LOGIN_CONSUMER_KEY,
TWITTER_LOGIN_CONSUMER_SECRET, ‘oob’, FALSE, array(
‘configuration’ => array(
‘provider_url’ => TWITTER_LOGIN_API_URL,
)
));
$consumer->write();
}
}[/php]

Now we can start building the core parts of the module that will initiate the authentication, and decide what to do once the user has enabled your application. Using hook_menu create a menu callback where you will send users to start the authentication process.

[php]
function twitter_login_menu(){
$items = array();
$items[‘twitter/login’] = array(
‘title’ => ‘Login’,
‘page callback’ => ‘twitter_login_login’,
‘access callback’ => TRUE,
‘type’ => MENU_CALLBACK,
);
}[/php]

In the page callback function we need to validate the consumer key and secret with Twitter in order to receive a URL(or a request token) to send the user off to for authentication. This authentication screen is where the magic happens, the user will be asked to login and enable your Twitter application on their Twitter account in case they havenʼt already done so. However, if the user is already logged into Twitter, and the application is already enabled on their account then they wonʼt see anything at all, they will just be forwarded on to the next step in the process.

[php]
function twitter_login_login(){
$callback = (!empty($_GET[‘callback’])) ? $_GET[‘callback’] : ‘user’;
if(TWITTER_LOGIN_CONSUMER_KEY and TWITTER_LOGIN_CONSUMER_SECRET){
$consumer_token = DrupalOAuthConsumer::load(TWITTER_LOGIN_CONSUMER_KEY, FALSE);
$sig_method = DrupalOAuthClient::signatureMethod(substr(strtolower(‘HMAC- SHA1’), 5));
$client = new DrupalOAuthClient(TWITTER_LOGIN_CONSUMER_KEY, NULL, $sig_method);
$request_token = $client->getRequestToken(‘/oauth/request_token’, array(
‘realm’ => null,
‘callback’ => url(‘oauth/authorized’, array(
‘absolute’ => TRUE,
‘query’ => array(‘callback’ => $callback),
)),
));
$request_token->write();
$_SESSION[‘oauthconnector_request_key’] = $request_token->key;
$request_token = $client->getAuthorizationUrl(‘/oauth/authenticate’,
array(
‘callback’ => url(‘oauth/authorized’, array(
‘absolute’ => TRUE,
‘query’ => array(‘callback’ => $callback),
)),
));
drupal_goto($request_token);
} else {
drupal_not_found();
}
}[/php]

In case you didnʼt notice, on the second line of the last snippet of code were pulling the callback variable from the URL query string, this works very much like the destination variable when logging into Drupal(ie: What is the users final destination after logging in?)

After the user has logged into Twitter and chosen to enable your application on their profile they are sent back to your site where you will now have access to their Twitter account. Itʼs probably a good idea to save their OAuth tokens using hook_oauth_common_authorized in case you need to use them later. This will prevent you from having to go through this process again.

In this example, before sending the user to the callback page, were going to tie the Twitter account with the logged in Drupal users using twitter_account_save function.

[php]
function twitter_login_oauth_common_authorized($consumer, $access_token,
$request_token){
parse_str($access_token, $access_token);
$twitter = new TwitterOAuth($consumer->key, $consumer->secret,
$access_token[‘oauth_token’], $access_token[‘oauth_token_secret’]);
if($twitter_user = $twitter->verify_credentials()){
$twitter_user->set_auth($access_token);
twitter_account_save($twitter_user, TRUE);
drupal_goto($_GET[‘callback’]);
} else {
drupal_access_denied();
}
}[/php]

Now that youʼve saved the users OAuth tokens to the database you can use the Twitter module to interact with their account and, based on your application permissions, access different Twitter function like sending or reading direct messages, and tweets.

Youʼll also want to keep in mind that because most Twitter data is public and they have a pretty strict set of terms that your application needs to abide by so youʼll want to check out their Developer Rules of the Road before doing anything too crazy with the API. If youʼre trying to integrate a different 3rd party application you can just