Authentication with Twitter OAuth

In this article we'll see how to authenticate our users via Twitter's OAuth mechanism, using Dancer::Plugin::Auth::Twitter.

This plugin is based on Net::Twitter and as a bonus side-effect exports a twitter keyword to the application's namespace, allowing other route handlers to access the whole Twitter API on behalf of the authenticated user.

This article will show you how to use that plugin to build a Twitter app with Dancer.

Basic OAuth principles

Explaining how OAuth works is beyond the scope of this article, on the other hand, you don't really need to understand the underlying logic of it to follow what will be done in this article. All you need to understand is that authentication with OAuth works with such a workflow:

  • An unauthenticated user requests a page on your app

  • The application requests an authentication URL from Twitter's API, providing its consumer_key and consumer_secret keys as well as a callback URL.

  • The application bounces the user to the authentication URL it has got from Twitter.

  • The user is redirected at Twitter and is prompted for allowing the application to access her profile and do actions on her behalf.

  • When the user hits the Allow button, she's redirected back to the application, on the callback URL provided before.

  • The user is back on the application, requesting the callback URL. The callback URL stores the user's information in a session and go back to the first route requested by the user.

  • The user is now authenticated.

First things first

Before starting we need to register a Twitter application so we can have our consumer_key and consumer_secret keys.

Anyone can register a Twitter application at http://dev.twitter.com, just make sure it is a Web application.

Configuring the plugin

First, our plugin needs a bit of configuration, as the application will need to know these consumer_key and consumer_secret keys.

Each Dancer plugin can store their configuration bits inside the main app's configuration, under plugins/PluginName. PluginName being the name of the plugin module minus the Dancer::Plugin namespace.

So as our plugin is named Dancer::Plugin::Auth::Twitter we'll be able to store our configuration under plugins/Auth::Twitter :

# config.yml
....
plugins:
  "Auth::Twitter":
    consumer_key: "abcd..."
    consumer_secret: "1234..."
    callback_url: "http://localhost:3000/auth/twitter/callback"

That's it! Our plugin is configured. We can now use it in our code.

Initialization

At the very first, we must initialize the plugin (basically it needs to read the configuration and create its internal Net::Twitter object). So our application must start with something like the following:

package MyApp;
use Dancer;
use Dancer::Plugin::Auth::Twitter;

auth_twitter_init();

At this point, if your app doesn't provide all the configuration bits needed by the plugin, it will throw an exception.

Filtering unauthenticated users

Implementing an authentication system basically relies on a before filter, where you check if the user is authenticated, and if not, redirect her to an authentication URL.

That is what we need to do here, and as you can see it's pretty straight-forward:

before sub {
    return if request->path =~ m{/auth/twitter/callback};
    if (not session('twitter_user')) {
        redirect auth_twitter_authenticate_url;
    }
};

This filter redirects any unauthenticated user to the authentication URL. Note that we don't want to do that redirection when the requested page is the callback URL defined by the plugin (this route handler is responsible for storing the authenticated user into the session).

With our filter though, all our application routes expect an authenticated Twitter user, you could of course do something more clever to enable that filter only for a subset of your routes, but that is left as an exercise for the reader.

Playing with Twitter

Well, at this point, we're done. Yes, it's that simple. The only work that is left to the developer is to provide a before filter that redirects unauthenticated users to auth_twitter_authenticate_url when appropriate. All the dirty work of communicating with Twitter is handled under the hood by Dancer::Plugin::Auth::Twitter.

So now, we can play with it, let's do a "Twitter hello world":

get "/" => sub {
    "Hello, ".session('twitter_user')->{'screen_name'};
};

As our before filter will catch any unauthenticated user and redirect them to Twitter if needed, it's that simple.

Note that the Net::Twitter object accessible via the twitter keyword allows you all that the Twitter ReST API provides, so your possibilities are endless.

More details

For more details about the plugin used in this article, you can check the example application that is shipped with Dancer::Plugin::Auth::Twitter in the example/ directory. It should be working out of the box.

The plugin described in this article is a port of Catalyst::Authentication::Credential::Twitter, huge kudos go to its authors.

Author

This article has been written by Alexis Sukrieh for the Perl Dancer advent calendar 2010.

Copyright

Copyright (C) 2010 Alexis Sukrieh <sukria@sukria.net>.