May 2013
Volume 28 Number 05
Cutting Edge - Social Authentication in ASP.NET MVC 4
By Dino Esposito | May 2013
As I see things, most Web sites that need to authenticate users will use social authentication gateways. In this context, a social authentication gateway is merely the authentication platform publicly exposed by popular social networks such as Twitter and Facebook. If you think back to the early days of ASP.NET, you can’t help but notice some likeness between the idea behind the Passport initiative and today’s social authentication gateways. They certainly aren’t the same thing, but in both scenarios you can recognize the goal of making users’ lives easier by reducing the number of credentials of which they must keep track.
Using the same set of credentials has pros and cons. On one hand it lowers the security barrier around your privacy. By always using the same username and password, you give hackers more time to guess your secrets; at the same time, you expose a lot more information once hacked. On the other hand, though, using the same credentials over and over makes it easier for you to connect and try out new services. For service owners this is great because they can see the number of users grow more quickly, which means the service has more chance to be successful.
In a nutshell, more and more Web sites aiming at attracting a large user base today offer the double option of registering by choosing your own credentials or through a social network authentication gateway. The trend is so interesting that in the newest version of ASP.NET MVC 4 you find an ad hoc framework to authenticate users via a number of social networks. In this article I’ll review the code you get from the ASP.NET MVC 4 project template. Social authentication gateways use the Open Authentication (OAuth) protocol, which turns out to be quite a verbose protocol. Therefore, the resulting code isn’t exactly trivial and may necessitate some further explanation.
The Quickest Way to MVC Authentication
ASP.NET MVC gives you the chance to start coding from a template of code that already includes authentication. The Internet Application template you get with ASP.NET MVC 4 extends the support to social gateways. Let’s assume, then, that you have a brand-new Internet Application project. On the first build of the code, nothing special happens. The page in Figure 1 informs you that no external authentication service has been enabled yet.
Figure 1 The ASP.NET MVC 4 Template When No External Authentication Service Is Configured
You can enable any of the supported services by making some light changes to the global.asax codebehind file. In ASP.NET MVC 4 it’s recommended that projects include an App_Start folder with xxxConfig classes that perform initialization tasks. Such classes are plain containers of static methods that better organize the bootstrapping code of the application. Here’s a snapshot:
protected void Application_Start()
{ ... AuthConfig.RegisterAuth();}
The RegisterAuth method contains the code to let users log in using their accounts from other sites such as Facebook and Twitter:
public static class AuthConfig
{
public static void RegisterAuth()
{
OAuthWebSecurity.RegisterTwitterClient(
consumerKey: yourTwitterAppKey
consumerSecret: yourTwitterAppSecret);
OAuthWebSecurity.RegisterFacebookClient(
appId: yourFacebookAppKey,
appSecret: yourFacebookAppSecret);
}
}
The OAuthWebSecurity class comes from the Web Pages framework and is located in the Microsoft.Web.WebPages.OAuth namespace. This class wraps up core functionality of the OAuth protocol as implemented in the DotNetOpenAuth (DNOA) library (see dotnetopenauth.net).
In order to authenticate users against a social network you first need to create an application within the social network. So you need a Twitter application and a Facebook application to authenticate users via Twitter and Facebook from within your site. Most likely you’ll create a Twitter/Facebook application with the same name as your site and configure it to link back to the Web site. What’s referenced here as a Twitter/Facebook application isn’t really a full-fledged application; moreover, it has a special developer token to programmatically access Twitter, Facebook and other social networks. In past installments of this column dedicated to Facebook programming I covered this aspect fairly in-depth. For the purpose of this article, a Twitter/Facebook application consists of a pair of strings—one known as the key and the other known as the secret. The key and secret are uniquely associated with the social application. You initialize OAuthWebSecurity by passing the key and secret for each social network you intend to support.
By simply adding calls to RegisterTwitterClient and RegisterFacebookClient, the UI of the sample project changes to show those registration options as buttons. If a user clicks the Log in button, she’ll be redirected to the Twitter/Facebook site to proceed with authentication. If it all works fine she’ll then be redirected to the original site and be recognized by ASP.NET as an authenticated user.
Sounds like a very simple thing, right? Well, there are a lot of nitty-gritty details under the hood.
Taking the OAuth Route to Authentication
When the user clicks on the Twitter button the site navigates to Account/ExternalLogin. Let’s have a look at the code for the method (the code is located in the AccountController.cs file):
public ActionResult ExternalLogin(String provider,
String returnUrl)
{
return new ExternalLoginResult(provider,
Url.Action("ExternalLoginCallback",
new { ReturnUrl = returnUrl }));
}
The ExternalLoginResult class is a sort of wrapper for the following code that really does the job of contacting the authentication gateway:
OAuthWebSecurity.RequestAuthentication(Provider, ReturnUrl);
The ExternalLoginResult class is a helper class also found in the AccountController.cs file. You should note that in the project template code the name of the provider is resolved by looking at the name attribute of the button:
<button type="submit"
name="provider"
value="@p.AuthenticationClient.ProviderName"
title="Log in using your @p.DisplayName account">
@p.DisplayName
</button>
At the end of the day, the RequestAuthentication method receives the name of the authentication provider (Twitter, Facebook or any of the other supported providers) and the URL to return. By default, OAuthWebSecurity supports the following providers: Twitter, Facebook, LinkedIn, Google, Microsoft and Yahoo. Internally, the method uses the DNOA library to carry the task. Let’s see what happens if the user chooses to authenticate via Twitter.
As a first step, the default Twitter authentication page is displayed to the user. The page contains the name of the Twitter application that’s conducting the task—it’s tFun in the sample shown in Figure 2. When you configure a Twitter application, you also indicate the permissions the user needs to grant to the application upon login. By properly configuring the social application you can give the ASP.NET Web site the permission to follow new users or post on behalf of the connected user. This isn’t the case with the sample application.
Figure 2 Authenticating via Twitter
If the user enters credentials that Twitter (or the social network of choice) recognizes as valid, the Twitter site redirects back to the provided return URL. The next method where you regain control past the authentication is ExternalLoginCallback. What you know at this point is only that the user who’s trying to access your application has been successfully recognized as a Twitter user. You don’t know anything about her, not even her username. I can hardly think of an application that needs authenticated users and can blissfully ignore usernames or e-mail addresses. Back from the authentication step, the application only receives a code but hasn’t yet been authorized to access the Twitter API programmatically. For this to happen, the code received at this stage must be exchanged for an access token (usually time-limited to prevent misuse). This is the purpose of the call to the method VerifyAuthentication you find in the body of ExternalLoginCallback. The AuthenticationResult object you get back from VerifyAuthentication brings back some information about the user. The actual information you get may be slightly different depending on the provider; however, it usually contains at least the username.
From Authentication to Membership
Authenticating a user is only the first step. Next, you need to track the user by name within the site. In a classic ASP.NET membership system you first display a login form, validate credentials, and then create an authentication cookie with username and, optionally, other key information. Twitter or Facebook save you the burden of arranging a login form and validating the credentials, plus the nontrivial burden of storing and managing accounts with sensitive information such as passwords.
The bottom line, though, is that nearly any application that needs authenticated users also needs a membership system where each regular user is tracked by name. Building such a system is still your responsibility. The ASP.NET MVC 4 template comes to the rescue by offering an extra step where the user is automatically given a chance to enter her display name, which is then saved to a local membership table. This is required only the first time a user logs in to a given site. In other words, the form shown in Figure 3 serves the purpose of joining registration and first login.
Figure 3 First Login and the Complete Registration to the Site
The name entered at this stage is used to create the ASP.NET authentication cookie, which definitely closes the circle. You used Twitter to check credentials, asked the user to enter her display name and created a regular authentication cookie. From now on, everything works as usual in ASP.NET for sites subject to authentication.
The default ASP.NET MVC 4 project template saves user data to an .mdf local database created under the App_Data folder. The table is managed using the simple membership API inherited from the Web Pages framework.
The following code shows how the sample project template gets the display name of the page of Figure 3:
var loginData = OAuthWebSecurity.SerializeProviderUserId(
result.Provider, result.ProviderUserId);
var name = OAuthWebSecurity
.GetOAuthClientData(result.Provider)
.DisplayName;
return View("ExternalLoginConfirmation",
new RegisterExternalLoginModel {
UserName = result.UserName,
ExternalLoginData = loginData
});
The call to GetOAuthClientData is where you access any information that the Twitter provider shares about the logged-in user. In the method ExternalLoginConfirmation two key things happen, summarized by the following code:
OAuthWebSecurity.CreateOrUpdateAccount(provider, providerUserId, model.UserName);
OAuthWebSecurity.Login(provider, providerUserId, createPersistentCookie: false);
The first line sets up the new record in the membership local database for the application. The second line actually creates the authentication cookie. The default template provides for a bunch of database tables such as UserProfiles and webPages_OAuthMembership. The latter table stores a record with the name of the provider (that is, Twitter), the provider unique ID for the user, and a pointer to an internal ID that uniquely identifies the user in the UserProfiles table with the display name the user herself chose in the page shown in Figure 3.
Final Considerations
The OAuth protocol manages the interaction between a provider and a client application. Twitter, Facebook and a few other popular social networks expose their APIs via OAuth. A client application can use the Twitter API for two main purposes: plain user authentication and operating against the provider on behalf of a consenting user. In both cases the client application must log in to the provider and get an access token. The access token is limited in time (but can programmatically be refreshed) and is authorized to perform only the operations that the end user approved when she entered credentials (see Figure 2). What happens once the application holds an access token depends on the needs of the application. The token can be used to retrieve, say, the e-mail address, and store it in an application-specific membership system. The token can also be used to post on behalf of the user. The ASP.NET authentication cookie remains valid even when the user disconnects from Twitter. An application, however, can’t post if the user is disconnected from Twitter.
The ASP.NET MVC API—specifically the OAuthWebSecurity class—addresses the authentication scenario nicely, but it doesn’t cover interacting with the social provider beyond getting a display name. It also integrates well with the simple membership provider of Web Pages for storing Twitter and Facebook user names locally.
Dino Esposito is the author of “Architecting Mobile Solutions for the Enterprise” (Microsoft Press, 2012) and “Programming ASP.NET MVC 3” (Microsoft Press, 2011), and coauthor of “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Based in Italy, Esposito is a frequent speaker at industry events worldwide. Follow him on Twitter at twitter.com/despos.
Thanks to the following technical expert for reviewing this article: Mani Subramanian (Microsoft)
Mani Subramanian has been involved in development and testing of software projects for the past 12 years with a focus on SOA, cloud computing and core.net.