Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET Identity 2.0: Introduction to Working with Identity 2.0 and Web API 2.2

0.00/5 (No votes)
6 Nov 2014 2  
In recent posts, I've covered a lot of ground using ASP.NET Identity 2.0 in the context of an MVC application. Since it's RTM in March of this year, Identity 2.0 has offered a substantial expansion of the Authentication/Authorization . toolset available to MVC applications. Similarly, Identity 2.0

Lock-320In recent posts, I've covered a lot of ground using ASP.NET Identity 2.0 in the context of an MVC application. Since it's RTM in March of this year, Identity 2.0 has offered a substantial expansion of the Authentication/Authorization . toolset available to MVC applications.

Similarly, Identity 2.0 expands the Identity management tools available through ASP.NET Web Api. The same flexibility and extensibility are available, although things work just a little differently.

In this post, I'm going to take a quick tour of a basic Identity 2.0-based Web Api application, and look at some basic usage examples. If you are an experienced web developer, there is probably nothing new for you here – this is intended to be a bit of a 101 level introduction. If you are new to Identity 2.0 and/or ASP.NET Web Api you will likely find some of this information useful.

Image by Universal Pops  |  Some Rights Reserved

In the next few posts, we'll take a closer look at using Identity 2.0 with Web Api. We'll see how to extend the Identity model, similar to what we did with Identity 2.0 for MVC. We'll create a more easily extensible Identity/Web Api project. We will also explore various Authentication and Authorization schemes, and develop a better understanding of effective Web Api security.

For a review of what we have covered on using Identity 2.0 in the context of an ASP.NET MVC project, see:

For now, we'll take a high-level look at the basic Web Api project template shipped with Visual Studio, and get familiar with the basic structure.

Getting Started - Create a New ASP.NET Web Api Project

As of Visual Studio 2013 Update 3, WebApi 2.0 and Identity 2.0 are part of the out-of-the-box Web Api project template. While this default project template is a bit cluttered for my tastes, it is a good starting point to get familiar with the basics.

We are going to create a basic Web Api project in visual studio, and then update the various Nuget packages. In part, because we generally want to tbe using the latest package versions, but in particular because we want to work with the latest release of Web Api (version 2.2 as of this writing, released in July 2014).

First, do File => New Project, and then select ASP.NET Web Application:

Create a New Web Application Project:

New Project

Update the Nuget Packages for the Solution

Then, Open the Nuget Package Manager and update the Nuget packages for the solution. Select "Update" from the sidebar on the left, then "Update All":

Update Nuget Packages for Solution:

update-nuget-packages

When you get partway through the update process, you will be greeted by a scary-looking window warning you that some project files are about to be overwritten. These are .cshtml View files, and SHOULD be overwritten, as they are being updated to work with the new libraries.

Resolve File Conflicts by Clicking “Yes to All”:

nuget-file-conflict-yes-to-all

View files, you say? I thought we were making a Web Api project?

We are. But as I said, the default Web Api project includes a bit 'o MVC, for the "Help" page, and a basic home page. More on this in a bit.

Run and Test the Default Web Api Project

Now that we have created a new Web Api project, let's give it a quick test spin and see if everything is working property.

Open another instance of Visual Studio, and create a console application. Next, use the Nuget package manager to install the Web Api Client Libraries:

Install Web Api Client Libraries into Console Application:

install-webapi-client-libraries-in-console-app

After the installation is complete, check for updates. Then, add the following code to the Program.cs file (be sure to add System.Net.Http and Newtonsoft.Json to the using statements at the top of the class):

Example code to run against Web Api Application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
 
namespace TestApi
{
    class Program
    {
        static void Main(string[] args)
        {
            string userName = "john@example.com";
            string password = "Password@123";
            var registerResult = Register(userName, password);
 
            Console.WriteLine("Registration Status Code: {0}", registerResult);
 
            string token = GetToken(userName, password);
            Console.WriteLine("");
            Console.WriteLine("Access Token:");
            Console.WriteLine(token);
            Console.Read();
        }
 
 
        static string Register(string email, string password)
        {
            var registerModel = new 
            { 
                Email = email, 
                Password = password, 
                ConfirmPassword = password 
            };
            using (var client = new HttpClient())
            {
                var response =
                    client.PostAsJsonAsync(
                    "http://localhost:62069/api/Account/Register", 
                    registerModel).Result;
                return response.StatusCode.ToString();
            } 
        }
 
 
        static string GetToken(string userName, string password)
        {
            var pairs = new List<KeyValuePair<string, string>>
                        {
                            new KeyValuePair<string, string>( "grant_type", "password" ), 
                            new KeyValuePair<string, string>( "username", userName ), 
                            new KeyValuePair<string, string> ( "Password", password )
                        };
            var content = new FormUrlEncodedContent(pairs);
            using (var client = new HttpClient())
            {
                var response = 
                    client.PostAsync("http://localhost:62069/Token", content).Result;
                return response.Content.ReadAsStringAsync().Result;
            }
        }
    }
}

Now, Run your Web Api application. Once it has finished starting up, run the new Console application.

What we are going to do here is POST content representing a new user to the Register() method defined on the AccountsController of our Api. Next, we will make a call to the Token endpoint of our Api and retrieve an access token, which we can use to authenticate ourselves during subsequent calls to our Api.

If you aren't quite sure what is happening in the code above, don't worry about it for the moment. We'll look more closely at what is going on here (and what this "token" business is all about) in a bit. For the moment, let's just see if our application works.

If all went as expected, our console output should look something like this:

Console Output from Register and GetTokenDictionary Methods:
resitration Status Code: OK
Access Token:
{"access_token":"8NeiVoKARt5Rm_50mP2ZfudNvvPRkm-FehohX8cLmUmrm1y8kZj0PTccsH1nKbT
PFTGuKoFSfi2mfD2KD-UMOEQWVJ0PJPfiSebJubSPLElzYfR7vk_V8gcbbkLK6cZ0zS7gWrMhdbgQrrQ
yDPyR83gbkjZcE1ooQQiv9d7AEfjCassj_R76Q44PW7goMHcbFZl66dZLBKGKhf9t7lpcvWStoyS6z8a
m7B3SWppVeaTjAC5BZ6uHOG1d_0mzL8FiR_eV8NaA1w3-GfV-upErG6xk5-qykdoLHoe7zmv4tX5Dm7-
w2n3G0gAdVlPcbfAJgSvu1AmUQe85g5ABbWJ6e0OXoPtH658kYZWC0FxbWiFPLGz66wPMbUCwjk_Hq_p
rLDjOshWP6lIE3qwQ88U5ScB1XcGAXbrYYFZ9AYkwSt4o5cC2Vpw8xP2OFdLdDOUs2ESPtVK8FThhaAh
yFUUDpXSlXwhQ2nEuu27ISw1MK0bh06-xx4vcnfoaW9XuHBXm","token_type":"bearer","expire
s_in":1209599,"userName":"john@example.com",".issued":"Wed, 17 Sep 2014 02:14:29
 GMT",".expires":"Wed, 01 Oct 2014 02:14:29 GMT"}

Congratulations! You have just registered a user, and retrieved an access token from your new Web Api application.

What you see in the console output is, first, the result from registering a new user. After that you see what looks like a gob of Json because, well, it is. We de-serialized the response content into a string, and an ginormous blob of JSON is what we get for that.

If you look close, you can see first the access_token property, and there at the end are a few other properties, such as token_type, a time until the token expires, userName, and a few other properties. We will be looking more closely at tokens shortly.

Now that we see everything is working, let's take a look at how the Web Api application is structured, and identify the important pieces we need to be aware of when working with Web Api and Identity. Then we'll learn a little more about this token business. 

Important Note: The code above is strictly to see if our application starts up and runs, and as an example of obtaining an access token. In reality, you would always want to implement SSL before sending/receiving Bearer tokens in this manner.

Web Api Project Structure - Overview

As mentioned previously, the default project template contains some fluff we may or may not wish to use in a "real" Web Api project. There is a folder named "Areas" which contains a bunch of stuff for managing a "help" page, there is a Views folder containing, well, a few .cshtml Views, and a few other folders mostly supporting the MVC side of our project, such as the Content folder, fonts folder, Etc. For the moment, it is safe to say we can ignore the following project folders (although they may be useful later on, depending upon your needs):

VS Web Api Project Folders we can Ignore (for now):

  • Areas folder
  • Content folder
  • Fonts folder
  • Scripts folder
  • Views folder

On the other hand, while we are getting started with Web Api and Identity 2.0, the following folders DO Matter to us, and form a critical part of the project structure. We need to be familiar with these in order to extend/adapt/customize the default project to our needs:

VS Web Api Project Folders we ARE Interested in:

  • App-Start folder
  • Controllers folder
  • Models folder
  • Providers folder

The App_Start Folder

The App_Start folder contains various configuration items which need to happen at… application startup. Of particular interest to us, from the context of an Identity-based Web Api application, are the files named IdentityConfig.cs, WebApiConfig.cs, and Startup.Auth.cs.

As the names of these files imply, these are each respectively where we might setup and/or modify configuration options for each of the services indicated. IdentityConfig.cs and Startup.Auth.cs are where we configure most of the authentication and authorization options for our application. WebApiConfig.cs is where we set up our default routes for incoming requests.

The Controllers Folder

This should be familiar to any who have worked with a basic MVC project before. However, note that controllers in a Web Api application are not the same as controllers in an MVC application - Web Api controllers all inherit from the ApiController base class, whereas the familiar MVC controller inherits from the Controller base class.

Controllers are where we process incoming Http requests, and either return the requested resource, or respond with the appropriate Http status code. We'll get a closer look at this soon.

The Models Folder

In a Web Api application, much like an MVC application, we define the business entities used by our application in terms of Models, ViewModels, and BindingModels. The Models folder is generally where we will find the business objects we need to make our application work.

As a general rule, Models represent core business objects, often persisted in our back-end data store. ViewModels generally represent the data required for use by a user of our Api. BindingModels are similar to Viewmodels, but they generally represent incoming data, and are used by the controller to deserialize incoming content from Xml or Json into objects our application can use.

The Providers Folder

In the default Visual Studio Web Api Solution, the Providers folder contains a single class, the ApplicationOAuthProvider. In the default configuration, this class is consumed by the ConfigureAuth() method defined on Startup.Auth, and defines how Authentication and Authorization tokens are handled.

Identity 2.0 and hence, Web Api 2.2 rely heavily on Owin as the default Authorization and Authentication middleware.

Default Identity Models for Web Api

If we start with the IdentityModels.cs file, we can see there isn't much going on here. We have a basic ApplicationUser class, and the ApplicationDbContext, and that's it:

The Identity Models Class:
public class ApplicationUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        UserManager<ApplicationUser> manager, string authenticationType)
    {
        // Note the authenticationType must match the one defined in 
        // CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
  
        // Add custom user claims here
        return userIdentity;
    }
}
  
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }
  
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }

The AccountViewModels.cs and AccountBindingModels.cs files contain the various ViewModels and BindingModels used by the AccountController methods. Pop those open and get a feel for what's there. The ViewModels represent what our Api expects to serialize and push OUT as content with a response, and the BindingModels generally represent data we expect to RECEIVE as content in an HTTP request, after being de-serialized by the appropriate format provider.

AccountController - an ApiController

Next let's take a look at AccountController. We won't walk through the code for this here in the post, but take a quick look at the various methods in this class. Many will look suspiciously similar to the AccountController in an MVC project. However, there are some important differences.

First off,  note that the methods on AccountController return either a data entity of some sort (such as the UserInfoViewModel returned by the GetUserInfo() method), or they return an instance of IHttpActionResult.

In other words, as we already suspected, Action methods on a Web Api controller don't return Views. They ultimately return HttpResponse messages (with some downstream assistance from the controller itself), with any content encoded in the response body.

By way of comparison, we find that the HomeController, also in the Controllers folder, inherits from the familiar Controller base class, and the Action methods defined on HomeController return the standard ActionResult, generally Views. That's because HomeController, here, is included to support the MVC component of our Web Api. We can ignore HomeController for now, as in currently doesn't provide access to any of our Api Methods.

Identity Configuration

In the App_Start folder, open the IdentityConfig.cs file. There's a lot less going on here than in the similar file found in a standard ASP.NET MVC project. Essentially, the only thing that happens here is that the ApplicationUserManager is defined for the Web Api Application. However, there are some important configuration items taking place here.

The ApplicationUserManager Class Defined in IdentityConfig.cs
    public static ApplicationUserManager Create(
        IdentityFactoryOptions<ApplicationUserManager> options, 
        IOwinContext context)
    {
        var manager = new ApplicationUserManager(
            new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
  
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
        
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(
                dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }
}

In this file, we define the password requirements for our application, as well as place potential constraints on user names and email addresses.

While not included in the default implementation for a Web Api project, this is also where we might define two-factor authentication providers for email or SMS text, and also where we might define email account confirmation configuration.

If we wanted to extend the Identity implementation in our Web Api application to include Roles, and some database initialization, this file is where we would most likely define and configure a RoleManager and DbInitializer.

Startup Authentication and Authorization Configuration

The primary authentication and authorization strategy in Web Api is token-based. We'll look closer at what this means momentarily, but for now, assume that in order to access any secured portion of your Api, you will need to present an access token as part of any incoming Http Request.

In the Startup.Auth.cs file, we se where configuration for authentication processing is performed. We see that the Startup.Auth.cs file contains a partial class, Startup, which extends the default Startup class defined at the root level of our project.

If we take a look at the latter (the Startup class at the root level of the project) we see a single method call, to the ConfigureAuth() method:

The Core Startup Class:
public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
    }
}

The ConfigureAuth() method is defined on the partial class in Startup.Auth.cs:

The ConfigureAuth Method from Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
    // Configure the db context and user manager to use a single instance per request
    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
  
    // Enable the application to use a cookie to store information for the signed in user
    // and to use a cookie to temporarily store information about a 
    // user logging in with a third party login provider
    app.UseCookieAuthentication(new CookieAuthenticationOptions());
    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
  
    // Configure the application for OAuth based flow
    PublicClientId = "self";
    OAuthOptions = new OAuthAuthorizationServerOptions
    {
        TokenEndpointPath = new PathString("/Token"),
        Provider = new ApplicationOAuthProvider(PublicClientId),
        AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
        AllowInsecureHttp = true
    };
  
    // Enable the application to use bearer tokens to authenticate users
    app.UseOAuthBearerTokens(OAuthOptions);
  
    // Uncomment the following lines to enable logging in with 
    // third party login providers
    //app.UseMicrosoftAccountAuthentication(
    //    clientId: "",
    //    clientSecret: "");
  
    //app.UseTwitterAuthentication(
    //    consumerKey: "",
    //    consumerSecret: "");
  
    //app.UseFacebookAuthentication(
    //    appId: "",
    //    appSecret: "");
  
    //app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
    //{
    //    ClientId = "",
    //    ClientSecret = ""
    //});
}

In this method, we configure options for cookie and token authentication, and, optionally, allow sign-in via various third-party providers such as Facebook or Twitter.

Of particular interest to us is the highlighted line configuring the application to use Bearer tokens. We'll find out why this is important soon enough. For now, realize that the Startup.Auth.cs file is where you configure the authorization and authentication options for the application as a whole, and determine what your application will, and won't, accept as credentials.

Token Authentication and Bearer Tokens

The standard Visual Studio Web Api template is configured to use OAuth bearer tokens as a primary means of authentication. Bearer Tokens are exactly what the name implies - Web Api will consider the bearer of the token to be properly authenticated (provided the token is not expired, per the configuration settings in Startup.Auth.cs).

This can have some serious security implications. If a malicious actor were able to intercept a client request and get hold of the Bearer Token from the request header, they would then be able to gain access as an authenticated Api user.

For this reason, if you are planning to deploy a Web Api application using the default Bearer Token authentication scheme, it is critical that the production application implement SSL/TSL(Meaning, HTTPS) to encrypt and protect traffic between the client an  your Api.

If we take another look at the console output when we ran our application earlier, we the information we grabbed from the token:

Contents of the Default Access Token:
registration Status Code: OK

Access Token:
{"access_token":"8NeiVoKARt5Rm_50mP2ZfudNvvPRkm-FehohX8cLmUmrm1y8kZj0PTccsH1nKbT
PFTGuKoFSfi2mfD2KD-UMOEQWVJ0PJPfiSebJubSPLElzYfR7vk_V8gcbbkLK6cZ0zS7gWrMhdbgQrrQ
yDPyR83gbkjZcE1ooQQiv9d7AEfjCassj_R76Q44PW7goMHcbFZl66dZLBKGKhf9t7lpcvWStoyS6z8a
m7B3SWppVeaTjAC5BZ6uHOG1d_0mzL8FiR_eV8NaA1w3-GfV-upErG6xk5-qykdoLHoe7zmv4tX5Dm7-
w2n3G0gAdVlPcbfAJgSvu1AmUQe85g5ABbWJ6e0OXoPtH658kYZWC0FxbWiFPLGz66wPMbUCwjk_Hq_p
rLDjOshWP6lIE3qwQ88U5ScB1XcGAXbrYYFZ9AYkwSt4o5cC2Vpw8xP2OFdLdDOUs2ESPtVK8FThhaAh
yFUUDpXSlXwhQ2nEuu27ISw1MK0bh06-xx4vcnfoaW9XuHBXm", "token_type":"bearer" ,"expire
s_in":1209599,"userName":"john@example.com",".issued":"Wed, 17 Sep 2014 02:14:29
 GMT",".expires":"Wed, 01 Oct 2014 02:14:29 GMT"}

We see that the token_type property identifies this as a Bearer token.

To use a rather cliché example, Bearer tokens can be compared to currency - they are valid for whoever presents them.

The examples we have used to this point, and for the rest of this article will be using standard HTTP. While you are developing your application or trying on the examples, this is fine. However, if you are going to deploy a production application you will most definitely want to implement SSL/TSL, or investigate alternative authentication/authorization schemes.

We will take a closer look at Tokens, and alternate authentication mechanisms in an upcoming post.

Using Token Authentication and Accessing Web Api from a Client Application

We've already seen how to obtain a basic bearer token from our Api. Now let's take a more detailed look at grabbing a token, and then making some requests against the basic, default Web Api project.

First, let's change up our code a little bit. What we want to do is pull apart the JSON token into a Dictionary<string, string> so we can get at the access_token property. It is this we need to submit in the header of subsequent Api requests in order to authenticate ourselves.

Change the GetToken() method as follows, so that instead of returning s string, it returns a Dictionary. Let's also rename it as GetTokenDictionary() to better reflect what it does:

The New GetTokenDictionary() Method:
static Dictionary<string, string> GetTokenDictionary(
    string userName, string password)
{
    var pairs = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>( "grant_type", "password" ), 
                    new KeyValuePair<string, string>( "username", userName ), 
                    new KeyValuePair<string, string> ( "Password", password )
                };
    var content = new FormUrlEncodedContent(pairs);
 
    using(var client = new HttpClient())
    {
        var response =
            client.PostAsync("http://localhost:62069/Token", content).Result;
        var result = response.Content.ReadAsStringAsync().Result;
 
        // Deserialize the JSON into a Dictionary<string, string>
        Dictionary<string, string> tokenDictionary =
            JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
        return tokenDictionary;
   }
}

Now let's update the Main() method to use our new dictionary, and write the various token properties out individually to the console:

Update Main() Method to Consume Deserialized Token Information:
static void Main(string[] args)
{
    string userName = "john@example.com";
    string password = "Password@123";
    var registerResult = Register(userName, password);
 
    Console.WriteLine("resitration Status Code: {0}", registerResult);
 
    //string token = GetToken(userName, password);
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
 
    // Write each item in the dictionary out to the console:
    foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
 
    Console.WriteLine("");
    Console.Read();
}

If we run the two applications now, we see the console output looks a little different:

Console Output Using the GetTokenDictionary() Method:
Registration Status Code: BadRequest

Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: zPrC7-CyHljhkPYQIDawhu7kgRd86p7oSJpRqHGifuANmEtM61syU5t6ciPGJrA3RX
I9u79IIOFaV3w5_GAQeF28DlUnc2HSkCxZsnqaYojLWfJ6gc8gfUlZo76SeJ7iO7MT6fdo8C5XgM_Geq
yun_8ykut9N456F41dI5PrrR6CyNc0ss_hy9OzdxnoqUdERglooNUrEcEt7WdZ9FHJ-cAi15fVPfV4z4
dUZZylrIyHuNSLVReet-zL769IEPvhgYixrp_hMgGQ6lDx8YMPTWvK_SVbe4W89DrHl1PbqfkiVgbJgJ
M09kmmIytNCFl_ua_GOdx1WyxXfPv0TLOmAgPX3klI4r_pglZl1QA0vihTN7zLsP2bkxIbMCBac3kq8z
4JT1JalxZ0OgArkW-Gy2qZJ-o-mPATCPUXLHtEd3z4lze17ECuCJyZzfLts3NN-hJgNwbmcqvGNvcakp
Y6SQ6U_ACdBJ3Q2JgZZeWf75pDupjeQbMhTqAPWUq9n35k
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Wed, 17 Sep 2014 02:55:45 GMT
.expires: Wed, 01 Oct 2014 02:55:45 GMT

First of all, why does it say "Bad Request" for our registration status code? We haven't changed THAT part of the code at all . . .  and there is the problem.

We have already registered a user named john@example.com, and Web Api has tossed back a validation error (the details of which are actually buried in the response content, but we'll worry about that later).

We can ignore that for now.

The next part of our console output is what we're interested in. Notice that, while the big, encrypted access_token still looks like a big blob of gibberish, our token as a whole is nicely split into its component properties on each line.

Now, let's try to access some of the Identity information from our Api. If we take a look at the AccountController in our Web Api project, we see there is a controller method named GetUserInfo() . Because our GetUserInfo() is decorated with the [Route] attribute “UserInfo" and our account controller [Route] attribute specifies a route of “api/Account” we know we can access this  method using the route “<host>/api/Account/UserInfo.”

Add the following static method to the Program class in our console application:

Add a GetUserInfo() Method to the Program Class:
static string GetUserInfo()
{
    using(var client = new HttpClient())
    {
        var response = 
            client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
        return response.Content.ReadAsStringAsync().Result;
    }
}

This simple method uses an instance of HttpClient to access the GetUserInfo() method on our AccountController, reads the response content as a string, and returns the result.

Now, we can call this method from the Main() method of our Console program and see what we get back. Update the Main() method of the Program class as follows:

Add a Call to GetUserInfo() to the Main() Method of the Program Class:
static void Main(string[] args)
{
    string userName = "john@example.com";
    string password = "Password@123";
    var registerResult = Register(userName, password);
 
    Console.WriteLine("Registration Status Code: {0}", registerResult);
 
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
 
    // Write each item in the dictionary out to the console:
    foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
 
    Console.WriteLine("");
 
    Console.WriteLine("Getting User Info:");
    Console.WriteLine(GetUserInfo());
}

Now, start your Web Api project again, wait for it to spin up completely, and then run the console application. Your console output should look something like this:

Console Output After Updating Client with Call to GetUserInfo() Method:
Registration Status Code: BadRequest

Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: c47uW0q-1qsIm88et81YqFzGz0Nt2GflLZJ3nLLDUPIS8epwMiBMkG9lCmF7-Rk8Ji
KA33JJkgtFl-3mjn78N-iQcX2pLxEsYf4h65njj2BaSRCSheCyfWY5WcS2MPipRFfwr1e-wx49R4Awo3
DHk2nJmMe_ARIASzw7Ger4gpJgNrqxt8B4QWcJyjgrr7RwK95alKQ4MY-ZlzJyNdWthdCSeykTvzLJQ-
rGjH7KT-SYwknyt62Fm2bwE7WzcudFgs1RIq8HDzuPiM9Fx9dBLhhPT2sCq8iV1dDFrCTnDsNoLA5ncG
y9BncGFb5fmkqibP1tV8k2xW0OxqaAuVz4jaS212--o2P9JQ5kCmC6gSYH0faBgNva3SV8uZnM64YoyY
gJ3i_lOql0pxxjtqJYUYQLYSDwzYVJXXl_PiKLHGrjZhtn480kzSdfkgdv1i-jiqap2ymzIeJjGcd6Tm
fePqCXeiKLUEO3FsOJ4VeRkXFXEkXpFBbuGWIe6N64M4M3
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Sun, 21 Sep 2014 00:56:49 GMT
.expires: Sun, 05 Oct 2014 00:56:49 GMT
 
Getting User Info:
{"Message":"Authorization has been denied for this request."}

But . . . wait. What happened? The last line, the result of our call to GetUserInfo() says authorization has been denied. What are we missing?

Notice that our AccountController class is decorated with an [Authorize] attribute in the class declaration. As you probably already realize, this mean that not just any old body can call into the AccountController. The class itself is decorated with the [Authorize] Attribute, so by default only authorized users can call Action methods defined on the class using HTTP. The Register() method has been decorated with an [AllowAnonymous] attribute, so unauthorized/unregistered users can register. but the rest of the methods are not accessible to unauthorized users.

In our case, despite the fact that we have actually obtained an access token from our Web Api by calling the Token endpoint of the Web Api application, we have not actually provided the token with our request to GetUserInfo().

Setting the Default Access Token For Web Api Requests

In order to create pass a token in with our HTTP requests, we can use the DefaultRequestHeaders property of HttpClient like so:

Set the Default Authorization Header for Client Requests:
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = 
    new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);

We can modify the GetUserInfo() method on our Program class like so:

Set Default Authorization Header on Request for GetUserInfo() Method:
static string GetUserInfo(string token)
{
    using(var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Authorization = 
        new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
 
        var response = client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
        return response.Content.ReadAsStringAsync().Result;
    }
}

Notice we are now passing an access token in as a method argument, specifying that it is a Bearer token, and then using that token to set in our default Authorization header.

Now, we simply need to pass that token to the method when we call it from Main() :

Pass the Access Token to GetUserInfo() when Calling from Main():
static void Main(string[] args)
{
    string userName = "john@example.com";
    string password = "Password@123";
    var registerResult = Register(userName, password);
 
    Console.WriteLine("Registration Status Code: {0}", registerResult);
 
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
 
    // Write each item in the dictionary out to the console:
    foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
 
    Console.WriteLine("");
 
    Console.WriteLine("Getting User Info:");
    Console.WriteLine(GetUserInfo(token["access_token"]));
}

Take note – we are not passing in the entire token dictionary returned from the GetToken() method here – only the actual access_token itself. In this code, we are pulling it out of our token dictionary using the ”access_token” key when we pass it as an argument to the GetUserInfo() method.

If we run the Console application now, we get the following:

Running the Console Application and Passing a Proper Auth Token:
Registration Status Code: BadRequest
Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: ygYowtlVKbwyd3J9Lown2Py2IcMEwGgjfS5YAbJJjlhADh4HURG6upqIah4zQjqLgH
MjlyuiwKEcpzDv95Y0OpIqGO5pU_I4MmHNnLttMFORDFo-u4B0q9KUsiGskHjt_q25cIy5ZZNAejmA4B
u8qJKuxWagK33-XlQYMD_USVTShfUFkjMpi7IxffPmjpzWl5ipUzxnu4t-4LpR87QuWwIv7novf_o8Sl
9EAXc7ySqDZ0SzB1WgtDK4or7oLeIFMkouwOD9PK-E3FJTTmfpPtXT6RIdL93FEYM5oxgxTiHSLt_cRL
1Mb5kyIILcl6dCR7OuGn_8QN3jabKOmXg5q5XE52m--BMzJwUESTzXjDge-_2XoNWI09jTki9RXWg2fV
PL7DIhSwSfIff8AE0hiZm2cvEYaqPHzej221TKI_YX9DQGOrtmfLLpxx_lmtfbN1rbnwYYSa51d_vPDV
yzsfZbC2vA-xzxWJS3LP4Qm_I8ZvJp-JKVu47Q-Y5Z0ZG_
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Sun, 21 Sep 2014 02:23:36 GMT
.expires: Sun, 05 Oct 2014 02:23:36 GMT
 
Getting User Info:
{"Email":"john@example.com","HasRegistered":true,"LoginProvider":null}

Now, that’s more like it.

Clean Up that Damn Code!

You may have notices that our examples have begun to take on some “code smells.” Well, for one, these are just examples, dammit. However, we can immediately see some opportunities to clean things up a bit, do a little refactoring.

How you would actually approach this would totally depend upon your specific project needs. But we can see right away that every time we go to access our Web Api from our client, we need an instance of HttpClient . Also, it is very likely that more often than not, we will need to be including an Auth token as part of our request.

We might add a static factory method, CreateClient() to handle this for us, and then call this from each of our client methods:

Add a CreateClient() Method (for example):
static HttpClient CreateClient(string accessToken = "")
{
    var client = new HttpClient();
    if(!string.IsNullOrWhiteSpace(accessToken))
    {
        client.DefaultRequestHeaders.Authorization = 
            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    }
    return client;            
}

Now, if a token is provided, the default Authorization header will be added. If not, an HttpClient will be returned without Authorization header.

Now, our GetUserInfo() method from the Console application might look like this:

Modified GetUserInfo() method:
static string GetUserInfo(string token)
{
    using(var client = CreateClient(token))
    {
        var response = client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
        return response.Content.ReadAsStringAsync().Result;
    }
}

We still have the using block, and we really only saved one line of code. However, the initialization of the HttpClient, and the setting of the access token now all happen in the same place.

A Note About Security, Bearer Tokens, and SSL

As mentioned earlier, an ASP.NET Web Api project uses Bearer tokens out of the box when using the default Visual Studio project template. In order to implement proper security, Api’s which use this sort of authentication should ALWAYS use SSL/TLS, especially when accepting user credentials in order to provide the access token at the Token endpoint.

What the Default ASP.NET Web Api Project does NOT Have

You may notice that there are no Role management methods, no RolesAdminController (or even a UserAdminController) in the basic Identity-based Web Api project. In fact, there are no Roles at all at this early stage. The AccountController contains methods sufficient to Register a new user, perform some basic management (such as changing passwords), and not much else.

If we want role-based authorization in our Web Api project, we will need to add it ourselves. Similarly, if we want a little more admin flexibility via our Api (or even using a few MVC pages within the application for GUI-based Administration), we will also need to add that ourselves.

Last, before we charge in adding Roles and such, we will want to examine whether Role-Based Authorization is the best fit for our needs. Identity 2.0, and Web Api easily support Claims-Based Authorization, which offers some distinct advantages for more complex authorization scenarios.

We will look at all of this, and more, in upcoming posts.

Looking Deeper into Identity 2.0 and Web Api

In this post, we’ve taken a very broad look at the structure of a Web Api 2.2 project, and where the major pieces of the Identity 2.0 framework fit. We’ve looked at using Bearer tokes as the default authentication mechanism, how to retrieve a token from your Api Token endpoint, and how to perform some very basic Api access.

In upcoming posts we will:

  • Look more closely at Token-based authentication and authorization, and how it relates to the familiar Users and Roles model we are familiar with
  • Extend Identity 2.0 models in the context of ASP.NET Web Api
  • Serializing and de-serializing Model data to and from HTTP requests and responses
  • Customizing Identity Management for Web Api
  • Creating an Authentication Service using Identity 2.0 and ASP.NET Web Api

This has been basically the 101-level introduction to using Identity 2.0 and ASP.NET Web Api. There is more to come, and a lot to understand in order to get the most out of the ASP.NET Identity framework in a Web Api context, and to properly secure a Web Api.

Additional Resources and Items of Interest

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here