Adding Twitter authentication support to ASP.NET application
In my last posting I introduced my idea about common membership provider for ASP.NET that is able to support multiple authentication providers. Before writing membership provider we need support for some authentication providers to get an better idea how to use them together. In this posting I will introduce you how to use OAuth protocol with Twitter.
Before we start …
… let me make some important notes and give some advises so you know better what is going on:
- OAuth is secure open-source authentication API that is used by Twitter and many other providers. You can find out more details about OAuth from their homepage at http://oauth.net/. There is also official specification for OAuth by Internet Engineering Task Force (IETF): The OAuth 1.0 Protocol.
- To make our sad lives easier there is library for .NET that makes it for us easier to support OAuth and OpenID protocols in our systems. This cool library is called DotNetOpenAuth. This library is also used by stackoverflow and MySpace. We will use the same library, so go and download it before starting with code.
- You need to register Twitter application. Go to page Twitter’s application registration page and register new application. You need consumer key and consumer secret parameters of your application later.
- Copy “Sign in with Twitter” to some of your web application’s folders where other images are. You need this button on logon page later.
- This is pretty raw stuff here and how to finish it so it works fine for you is up to you this time.
- I am sorry for format of code but I found no better way to get it more readable here. When my new blog is finished somewhere in future then there will be way better layout that is designed with .NET code in mind. This far, please survive my current blog! :)
I suppose you can Twitter application registered by yourself and also it should not be very hard to download DotNetOpenAuth and add it to your ASP.NET MVC application.
Token manager
Before we can connect to Twitter we need token manager that handles security tokens. Right now we will use InMemoryTokenManager that comes with Twitter application block for Enterprise Library (you can find it from samples folder of your DotNetOpenAuth download). The class is here, you can take it using copy and paste. I removed code documentation from this class because I plan to replace it later by my own token manager.
internal class InMemoryTokenManager
: IConsumerTokenManager, IOpenIdOAuthTokenManager
{
private Dictionary<string, string> tokensAndSecrets =
new Dictionary<string, string>();
public InMemoryTokenManager(string consumerKey, string consumerSecret)
{
if (String.IsNullOrEmpty(consumerKey)) {
throw new ArgumentNullException("consumerKey");
}
this.ConsumerKey = consumerKey;
this.ConsumerSecret = consumerSecret;
}
public string ConsumerKey { get; private set; }
public string ConsumerSecret { get; private set; }
public string GetTokenSecret(string token) {
return this.tokensAndSecrets[token];
}
public void StoreNewRequestToken(UnauthorizedTokenRequest request,
ITokenSecretContainingMessage response)
{
this.tokensAndSecrets[response.Token] = response.TokenSecret;
}
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey,
string requestToken, string accessToken, string accessTokenSecret)
{
this.tokensAndSecrets.Remove(requestToken);
this.tokensAndSecrets[accessToken] = accessTokenSecret;
}
public TokenType GetTokenType(string token)
{
throw new NotImplementedException();
}
public void StoreOpenIdAuthorizedRequestToken(string consumerKey,
AuthorizationApprovedResponse authorization)
{
this.tokensAndSecrets[authorization.RequestToken] = String.Empty;
}
}
This class may seem a little bit complex at first place but when you have Twitter connected and you play with it a little bit then you get the idea. There is really nothing complex and implementing you own token manager should be easy.
Twitter client
Now let’s write Twitter client. This is class that does all the dirty work for us. It is better for us to have this class instead of pushing all this functionality to our logon page controller methods. For one authentication provider it doesn’t seem like very bad sin but if we have three or five different authentication providers supported then our logon page controller will look like war field. So, let’s fight against chaos right from start.
public class TwitterClient
{
private string UserName { get; set; }
private static readonly ServiceProviderDescription ServiceDescription =
new ServiceProviderDescription
{
RequestTokenEndpoint = new MessageReceivingEndpoint(
"http://twitter.com/oauth/request_token",
HttpDeliveryMethods.GetRequest |
HttpDeliveryMethods.AuthorizationHeaderRequest),
UserAuthorizationEndpoint = new MessageReceivingEndpoint(
"http://twitter.com/oauth/authorize",
HttpDeliveryMethods.GetRequest |
HttpDeliveryMethods.AuthorizationHeaderRequest),
AccessTokenEndpoint = new MessageReceivingEndpoint(
"http://twitter.com/oauth/access_token",
HttpDeliveryMethods.GetRequest |
HttpDeliveryMethods.AuthorizationHeaderRequest),
TamperProtectionElements = new ITamperProtectionChannelBindingElement[]
{ new HmacSha1SigningBindingElement() },
};
IConsumerTokenManager _tokenManager;
public TwitterClient(IConsumerTokenManager tokenManager)
{
_tokenManager = tokenManager;
}
public void StartAuthentication()
{
var request = HttpContext.Current.Request;
using (var twitter = new WebConsumer(ServiceDescription, _tokenManager))
{
var callBackUrl = new Uri(request.Url.Scheme + "://" +
request.Url.Authority + "/Account/TwitterCallback");
twitter.Channel.Send(
twitter.PrepareRequestUserAuthorization(callBackUrl, null, null)
);
}
}
public bool FinishAuthentication()
{
using (var twitter = new WebConsumer(ServiceDescription, _tokenManager))
{
var accessTokenResponse = twitter.ProcessUserAuthorization();
if (accessTokenResponse != null)
{
UserName = accessTokenResponse.ExtraData["screen_name"];
return true;
}
}
return false;
}
}
Our TwitterClient has two methods. StartAuthentication() is called when user clicks on Twitter button. FinishAuthentication() is called in Twitter authentication callback page to finalize authentication procedure. As a next thing I will show you how to mix all together.
Logon page
Okay, I expect you have default ASP.NET MVC application with AccountController and no markable modifications there. Let’s go now through changes using minimal steps. As a first let’s open LogOn.aspx view and add the following markup there.
<a href="<%= Url.Content("~/Account/StartTwitterAuth/") %>">
<img src="<%= Url.Content("~/images/sign-in-with-twitter-darker.png") %>" />
</a>
Now let’s open AccountController and add the following lines of code to the beginning of controller class.
static private readonly InMemoryTokenManager TokenManager =
new InMemoryTokenManager("<consumerKey>", "<consumerSecret>");
Replace <consumerKey> and <consumerSecret> with values you got from your Twitter application page. I know it is not nice solution but it works for me now and of course I will let you know how to solve it better as soon as I work out better solution.
Now add two new controller methods to AccountController.
public ActionResult StartTwitterAuth()
{
var client = new TwitterClient(TokenManager);
client.StartAuthentication();
return null;
}
public ActionResult TwitterCallback()
{
var client = new TwitterClient(TokenManager);
if (client.FinishAuthentication())
{
return new RedirectResult("/");
}
// show error
return View("LogOn");
}
Now we have Twitter support added to our ASP.NET MVC application.
Testing Twitter authentication
After compiling your application put breakpoint to TwitterCallback method on the line where redirect is made. Now run your application and log in using Twitter. When application starts go to log on page and click on Twitter button. After successfully logging in the breakpoint will be hit. Check out the value in UserName property of variable called client. You sould see there you Twitter username.
Conclusion
Getting Twitter authentication work with ASP.NET MVC using DotNetOpenAuth was pretty simple thing to do. There was also no complex issues from Twitter side and everything started to work smoothly. Besides Twitter there are many other sites that provide authentication options to external applications using OAuth protocol. With little modifications to code provided here you can use some other provider instead of Twitter or add additional OAuth providers to your ASP.NET MVC application.