June 2014

Volume 29 Number 6

Cutting Edge : External Authentication with ASP.NET Identity

Dino Esposito | June 2014

Dino EspositoVisual Studio 2013 includes new ASP.NET MVC 5 and Web Forms project templates for building applications. The sample templates might optionally contain a default authentication layer based on ASP.NET Identity. The code generated for you contains a lot of features, but it might not be that easy to read. In this article, I’ll show how to perform authentication through an external OAuth- or OpenID-based server such as a social network and the steps you might want to take once authentication is complete and you have access to all the downloaded claims.

I’ll start with an empty ASP.NET MVC 5 application and add the bare minimum authentication layer an app might need. You’ll see the new ASP.NET Identity framework brings a new level of complexity and power to the whole authentication stack, but, at the same time, it makes it quick and easy to arrange for external user authentication without any need for you to learn new packages and APIs.

Factoring Out the Account Controller

Since the very first release of ASP.NET MVC, the sample application that represents the face of the framework to new users offered a rather bloated controller class to manage all aspects of authentication. In my March 2014 column, “A First Look at ASP.NET Identity” (msdn.microsoft.com/magazine/dn605872), I provided an overview of the ASP.NET Identity framework starting from the code you get by default in Visual Studio. This time, instead, I’ll put the various pieces together starting from an empty ASP.NET MVC 5 project. In doing so, I’ll carefully follow the Single Responsibility Principle (bit.ly/1gGjFtx).

I’ll start with an empty project and then add some ASP.NET MVC 5 scaffolding. Next, I’ll add two new controller classes: Login­Controller and AccountController. The former is only concerned with sign-in and sign-out operations whether accomplished through the site-specific, local membership system or an external OAuth provider such as Twitter. As the name itself suggests, the AccountController class includes any other functionality mostly related to the management of the user accounts. For the sake of simplicity, I’ll only include the ability to register a new user at this time. Figure 1 shows the skeleton of the two controller classes, as they appear in Visual Studio 2013.

Skeleton of LoginController and AccountController Classes in Visual Studio 2013
Figure 1 Skeleton of LoginController and AccountController Classes in Visual Studio 2013

The UI is articulated in three partial views: logged user, local login form and social login form, as shown in Figure 2.

The Three Partial Views Used in the Authentication Stack
Figure 2 The Three Partial Views Used in the Authentication Stack

The IdentityController Class

In the skeleton shown in Figure 1, both the LoginController and AccountController classes inherit from the base ASP.NET MVC 5 Controller class. If you’re going to use the ASP.NET Identity framework, however, this might not be the ideal choice, as it could lead to some duplicated code. I suggest you create a temporary project in Visual Studio 2013 and take a look at the default code stored in the almighty and all-encompassing AccountController class. ASP.NET Identity requires you to inject the UserManager<TUser> class and the storage mechanism into the controller. In addition, you might want to have a couple of helper methods to simplify the process of signing users in and redirecting. You also need a couple of properties to reference the UserManager root object and maybe yet another helper property to establish a point of contact with the underlying Open Web Interface for .NET (OWIN) middleware.

It’s probably a good idea to introduce an intermediate class where all this boilerplate code can be comfortably stuffed once and only once. I’ll call this class IdentityController and define it as shown in Figure 3.

Figure 3 A New Base Class for ASP.NET Identity Authentication

using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using AuthSocial.ViewModels.Account.Identity;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin.Security;
namespace AuthSocial.Controllers
{
  public class IdentityController<TUser, TDbContext> : Controller
  where TUser : IdentityUser
  where TDbContext : IdentityDbContext, new()
  {
    public IdentityController()
    : this(new UserManager<TUser>(
    new UserStore<TUser>(new TDbContext())))
    {
    }
    public IdentityController(UserManager<TUser> userManager)
    {
      UserManager = userManager;
    }
    protected UserManager<TUser> UserManager { get; set; }
    protected IAuthenticationManager AuthenticationManager
    {
      get { return HttpContext.GetOwinContext().Authentication; }
    }
    protected async Task SignInAsync(
      TUser user, bool isPersistent)
    {
    AuthenticationManager.SignOut(
    defaultAuthenticationTypes.ExternalCookie);
      var identity = await UserManager.CreateIdentityAsync(user,
        DefaultAuthenticationTypes.ApplicationCookie);
      AuthenticationManager.SignIn(
        new AuthenticationProperties {
          IsPersistent = isPersistent },
          identity);
        }
      protected ActionResult RedirectToLocal(string returnUrl)
      {
        if (Url.IsLocalUrl(returnUrl))
        {
          return Redirect(returnUrl);
        }
        return RedirectToAction("Index", "Home");
      }
      protected ClaimsIdentity GetBasicUserIdentity(string name)
      {
        var claims = new List<Claim> {
          new Claim(ClaimTypes.Name, name) };
        return new ClaimsIdentity(
          claims, DefaultAuthenticationTypes.ApplicationCookie);
      }
  }
}

The use of generics—and related constraints—binds the IdentityController class to use any definition of a user based on the IdentityUser class and any definition of a storage context based on IdentityDbContext.

IdentityUser, in particular, is just the basic class to describe a user and offer a minimal set of properties. You’re welcome to create new and more specific classes through plain inheritance. When you do this, you just specify your custom class in the declaration of classes derived from IdentityController. Here’s the declaration of LoginController and AccountController based on IdentityController<TUser, TDbContext>:

public class LoginController :
  IdentityController<IdentityUser, IdentityDbContext>
{
  ...
}
public class AccountController :
  IdentityController<IdentityUser, IdentityDbContext>
{
  ...
}

In this way, you set the groundwork for partitioning most of the complexity of authentication and user management code across three classes. Moreover, you now have one class to provide common services and one class that just focuses on login tasks. Finally, you have a separate class to deal with management of user accounts. I’ll just start from the account class, where, for the sake of simplicity, I only expose an endpoint to register new users.

The AccountController Class

Generally, you need a controller method only if there’s some piece of displayed UI with which the end user interacts. If there’s, say, a submit button the user can click, then you need a POST-sensitive controller method. In order to define this method, start from the view model for it. The view model class is a plain Data Transfer Object (DTO) that gathers together any data (strings, dates, numbers, Booleans and collections) that goes in and out of the displayed UI. For a method that adds a new user into the local membership system, you can have the following view model class (the source code is the same as what you get from the default Visual Studio 2013 ASP.NET MVC 5 template):

public class RegisterViewModel
{
  public string UserName { get; set; }
  public string Password { get; set; }
  public string ConfirmPassword { get; set; }
}

You might also want to decorate this class with data annotations for validation and display purposes. At a higher design level, though, all that matters is that the class features one property for each input control in the actual UI. Figure 4 presents the implementation of the controller method that handles the POST request to register a new user.

Figure 4 Registering a New User

public async Task<ActionResult> Register(
  RegisterViewModel model)
{
  if (ModelState.IsValid) {
    var user = new IdentityUser { UserName = model.UserName };
    var result = await UserManager.CreateAsync(
      user, model.Password);
    if (result.Succeeded) {
      await SignInAsync(user, false);
      return RedirectToAction("Index", "Home");
    }
  Helpers.AddErrors(ModelState, result);
  }
  return View(model);
}

The CreateAsync method on the UserManager class just uses the underlying storage mechanism to create a new entry for the specified user. This AccountController class is also the ideal place to define other methods to edit or just delete user accounts and change or reset passwords.

The LoginController Class

The login controller will feature methods to sign users in and out in any way that’s acceptable for the application. Similarly to what I discussed about the account controller, the SignIn method will manage a DTO with properties to carry credentials, a flag for the authentication persistence and perhaps a return URL. In the default code, the return URL is managed through the ViewBag; you can stuff it in the view model class as well:

public class LoginViewModel
{
  public string UserName { get; set; }
  public string Password { get; set; }
  public bool RememberMe { get; set; }
  public string ReturnUrl { get; set; }
}

The code to interact with the local membership system, entirely managed on the application server, is pasted in from the default project. Here’s an excerpt from the POST implementation of the new SignIn method:

var user = await UserManager.FindAsync(
  model.UserName, model.Password);
if (user != null)
{
  await SignInAsync(user, model.RememberMe);
  return RedirectToLocal(returnUrl);
}

The code that ultimately signs in users is a method—named SignInAsync—borrowed from the default implementation and rewritten as a protected method in the IdentityController base class:

protected async Task SignInAsync(TUser user, bool isPersistent)
{
  AuthenticationManager.SignOut(
  DefaultAuthenticationTypes.ExternalCookie);
  var identity = await UserManager.CreateIdentityAsync(user,
    DefaultAuthenticationTypes.ApplicationCookie);
  AuthenticationManager.SignIn(
    new AuthenticationProperties { IsPersistent = isPersistent },  
  identity);
}

When using the ASP.NET Identity framework, you don’t use any class that’s explicitly related to the ASP.NET machinery. In the context of an ASP.NET MVC host, you still manage user authentication through login forms and ASP.NET authentication cookies—except that you don’t use the FormsAuthentication ASP.NET class directly. There are two layers of code with which classic ASP.NET developers need to cope. One is the plain ASP.NET Identity API represented by classes such as UserManager and IdentityUser. The other is the OWIN cookie middleware, which just shields the façade authentication API from the nitty-gritty details of how a logged user’s information is stored and persisted. Forms authentication is still used, and the old acquaintance, the .ASPXAUTH cookie, is still created. However, everything now happens behind the curtain of a bunch of new methods. For a deeper understanding of this, see Brock Allen’s blog post, “A Primer on OWIN Cookie Authentication Middleware for the ASP.NET Developer,” at bit.ly/1fKG0G9.

Look at the following code you find invoked right from Startup­Auth.cs, the entry point for OWIN middleware :

app.UseCookieAuthentication(
  new CookieAuthenticationOptions
{
  AuthenticationType =
    DefaultAuthenticationTypes.ApplicationCookie,
  LoginPath = new PathString("/Login/SignIn")
});
app.UseExternalSignInCookie(
  DefaultAuthenticationTypes.ExternalCookie);
app.UseTwitterAuthentication(
  consumerKey: "45c6...iQ",
  consumerSecret: "pRcoXT...kdnU");

This code is a sort of a fluent interface you use instead of the old-fashioned web.config authentication entries. In addition, it also links in Twitter-based authentication and configures the OWIN middleware to use the ExternalSignInCookie in order to temporarily store information about a user logging in through a third-party login provider.

The object AuthenticationManager represents the entry point in the OWIN middleware and the façade through which you invoke the underlying ASP.NET authentication API based on FormsAuthentication.

The net effect is you end up using a unified API to authenticate users and verify credentials whether the membership system is local to your Web server or externally delegated to a social network login provider. Here’s the code you use if it’s acceptable that users of your site authenticate via their Twitter accounts:

[AllowAnonymous]
public ActionResult Twitter(String returnUrl)
{
  var provider = "Twitter";
  return new ChallengeResult(provider,
    Url.Action("ExternalLoginCallback", "Login",
    new { ReturnUrl = returnUrl }));
}

First and foremost, you need to have a Twitter application configured and associated with a Twitter developer account. For more information, see dev.twitter.com. A Twitter application is uniquely identified by a pair of alphanumeric strings known as consumer key and secret.

The default code you get from the ASP.NET MVC 5 project wizard also suggests you use an entirely new class—ChallengeResult—to handle external logins, shown in Figure 5.

Figure 5 The ChallengeResult Class

public class ChallengeResult : HttpUnauthorizedResult
{
  public ChallengeResult(string provider, string redirectUri)
  {
    LoginProvider = provider;
    RedirectUri = redirectUri;
  }
  public string LoginProvider { get; set; }
  public string RedirectUri { get; set; }
  public override void ExecuteResult(ControllerContext context)
  {
    var properties = new AuthenticationProperties
    {
      RedirectUri = RedirectUri
    };
    context.HttpContext
           .GetOwinContext()
           .Authentication
           .Challenge(properties, LoginProvider);
  }
}

The class delegates to the OWIN middleware—in the method named Challenge—the task to connect to the specified login provider (registered at startup) to carry out authentication. The return URL is the method ExternalLoginCallback on the login controller:

[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(
  string returnUrl)
{
  var info = await AuthenticationManager.GetExternalLoginInfoAsync();
  if (info == null)
    return RedirectToAction("SignIn");
  var identity = GetBasicUserIdentity(info.DefaultUserName);
  AuthenticationManager.SignIn(
    new AuthenticationProperties { IsPersistent = true },
    identity);
  return RedirectToLocal(returnUrl);
}

The method GetExternalLoginInfoAsync retrieves information about the identified user that the login provider makes available. When the method returns, the application has enough information to actually sign the user in, but nothing has happened yet. It’s important to be aware of the options you have here. First, you can simply proceed and create a canonical ASP.NET authentication cookie, as in my example. Defined in the IdentityController base class, the helper method GetBasicUserIdentity creates a ClaimsIdentity object around the provided Twitter account name:

protected ClaimsIdentity GetBasicUserIdentity(string name)
{
  var claims = new List<Claim> { new Claim(
    ClaimTypes.Name, name) };
  return new ClaimsIdentity(
    claims, DefaultAuthenticationTypes.ApplicationCookie);
}

Once the Twitter user authorizes the Twitter application to share information, the Web page receives the user name and potentially more data, as shown in Figure 6 (this depends on the actual social API being used).

The Classic Twitter-Based Authentication
Figure 6 The Classic Twitter-Based Authentication

Notice in the preceding code that in the ExternalLoginCallback method no user is added to the local membership system. This is the simplest scenario. In other situations, you might want to use the Twitter information to programmatically register a link between a local login and the externally authenticated user name (this is the solution presented in the default authentication code from the wizard). Finally, you can decide to redirect users to a different page to let them enter an e-mail address or just register for your site.

Mixing Classic and Social Authentication

Some level of authentication is necessary in nearly every Web site. ASP.NET Identity makes it easy to code and mix classic and social authentication behind a unified façade. It’s important, though, that you have a clear strategy about the way you want to handle accounts for users and what information you want to collect and store about them. Mixing classic and social authentication means you can have an individual user account and associate it with multiple login providers such as Facebook, Twitter and all other login providers supported by ASP.NET Identity. In this way, users have multiple ways to sign in, but they remain unique to the eyes of your application. And more login providers can be added or removed as is convenient.


Dino Esposito is the author of “Architecting Mobile Solutions for the Enterprise” (Microsoft Press, 2012) and the upcoming “Programming ASP.NET MVC 5” (Microsoft Press). A technical evangelist for the .NET Framework and Android platforms at JetBrains and frequent speaker at industry events worldwide, Esposito shares his vision of software at software2cents.wordpress.com and on Twitter at twitter.com/despos.

Thanks to the following Microsoft technical expert for reviewing this article: Pranav Rastogi