Using OAuth with MVC5 WebApi

For the last couple of weeks, I’ve been involved with a project which includes several sub-projects that will need to communicate with each other, and with a credit card processor (Authorize.net).  In addition, other applications will call into this one to handle payment processing business logic.  In developing this project, I’m focused on making sure the Web API is more Restful (REST) than previous RPC style Web API projects I’ve worked on. Also, since this API will handle customer and payment information, this one needs to be very secure.  My research and work has been interesting, and since good documentation and explanations have been hard to find, I’ll layout what I’ve found to be most helpful.

My goal has been to utilize the OWIN and OAuth utilities already contained in .Net MVC5 and then to layer best practices on top of that. With that in mind, I found a great video describing OAuth at http://vimeo.com/user22258446/review/79095048/9a4d62f61c . This article builds on the information I learned in that video by reviewing what I felt was most important, and filling in a few gaps.

There are a  few points to keep in mind about OAuth:

  1. There are 3 entities involved in the OAuth process:
    1. The ‘Client’ (browser, a server application, an Iphone app, etc.)
    2. The ‘Authentication Server’ (verifies the identity (username and password)), and delivers a token to be used.
    3. The ‘Resource Server’ (The the application that needs to be secured and does the work we are interested in.)
  2. The ‘Client’ is interested in communicating with the ‘Resource Server’.
  3. The ‘Resource Server’ allows the ‘Authentication Server’ to be responsible for authentication (verifying a user is who they say they are).
  4. The ‘Authentication Server’ might be Google, Facebook, Twitter, your employer’s service, or it may be included in ‘Resouce Server’ project.
    1. In ASP.Net MVC5 project setup for ‘Individual Accounts’, by default, your application will act as both ‘Authentication Server’ and ‘Resource Server’ but it important that even if you do that, that you understand that these are 2 separate roles. Also, if you do that, you could change the ‘Authentication Server at any time to be some other service, or you could add additional ‘Authentication Servers’ (ex. an app could allow people to login using AD, Google, and Facebook identities).
  5. ‘Authentication Servers’ create access tokens that are used to prove identity to a ‘Resource Server’. The Client gives a username and password to the ‘Authentication Server’ and the ‘Authentication Server’ returns a token to the client. The token has an expiration date such as 14 days after the day it issued. The client can save the token and use that token every time it accesses the ‘Resource Server’ until the token becomes invalid or expires. Then the Client repeats the process to get a new token, and uses that until it expires.
  6. The token becomes proof that you are an authenticated user so it is important that tokens are protected as if they are a username and password.  Use SSL (!!!) when transmitting the token from the Client to the Resource Server on every single trip!
  7. Use SSL on every single trip!
  8. Now if you are wondering why passing a token beats passing username and password on each trip, it is because the token has an expiration and it can be voided by the ‘Authentication Server’.  So if someone gets your token, it is valid for a limited time. Also if you use the same password all the time (which you don’t of course ), then they wouldn’t be able to try to login as you at other services.

 

Let’s look at few images to get a visual concept of how Clients (human or machine) authenticate, and then communicate with the ‘Resource Server’.

 

Ideally, you would completely separate the Authentication Server from Resource Server. The resource application would still be responsible for authorization (what you are allowed to access, what roles you belong to etc.). This version is common if you allow people to login using their Google account or Facebook account. The process looks like this:

3 Party Authentication Process

 

We are going to combine the Authentication Server and Resource Server into the same application. The same processes occur but we only need a single website (or web service) to act as both Authentication Server and Resource Server.  It will look like this:

Two party authentication

You can start your project like this and later you can add more Authentication Servers, for instance you could add Google and FaceBook authentication later. I’ll save that for another article.

For this sample, we’ll make it a Payment Processor application. The scenario is that this application will make calls receive calls from other applications One of those other applications is a website that customers access to manage their accounts, and the other is a application that customer service employees use to manage customer accounts.  Both applications will need to be able to perform CRUD operations on:

  1. Customers
  2. PaymentProfiles (credit cards or bank accounts for customers)
  3. Transactions (payments, refunds, voids)

This application will interact  with a local database, and with Authorize.Net on the back end. I’m not including the Authorize.Net code in this article, but may write another article later for that.  Let’s start by creating our app.

Create a new ASP.Net Web ApplicationCreating WebApi 1

Select ASP.Net Web Application, give it a name and a folder, and click OK.

Creating webApi 2

 

After you click OK, select Web API, then click the Change Authentication button. Make sure that you have it set to ‘Individual Accounts’.

Individiual Accounts setting

Click Ok on both of those windows to create your new Web API project.

 

Now your project has been created, and if you click debug you can run it and it will display the generic looking home page. The application has a Home page and a Help page, which describes the available API functions.

New WebApi

Customizing your application:

You could leave the default connection string in your web.config, and use a SQL Express database if you like, but I’m going to create a new database on my local SQL 2008 server and point the connection string to that. I opened SQL 2008’s SSMS interface and created a new, empty database named ‘PaymentProcAPI’. Then I edited my connection string as follows:

Connection String

 

 

Adding A User Account to the database

Let’s create a little throw away website just to add a user account to our database. I’m assuming you are familiar with creating website in VS 2013 so I’ll run through this quickly.

  1. Right click your solution and click ‘Add Project’ and then select ASP.Net Web Application’. Enter a name of ‘UserRegistrationSite’. Click Ok.
  2. Select MVC, and click Change Authentication. Select ‘Individual Accounts’ and click OK. Click OK again to close the window. Your new application is created.
  3. Copy the connection string from the web.config in your PaymentProcessorAPI project and replace the connection string in this new website with it. Both sites must be hitting the same database. Run this application and click the Login button on the header.
  4. Click the ‘Register’ link
  5. Add a user account.
  6. Once your user account is created you are finished with this website for this exercise.

For my user I’ve created Marctalcott@marctalcott.com as my user account. You have created a user by the name of your choice.  Now if I look in the database, that I setup, I see a set of tables have been added and there is a row in the AspNetUsers table for my new user. The user has a guid Id, Email, UserName, PasswordHash, and other fields. You can check your database to see if this has all worked properly.

 

UserTablesAddedToDb

 

Then I added some model classes in my Model Folder. You can go ahead and add these to your Model’s folder.

    public class CustomerProfile
    {
        public long Id { get; set; }
        public string First { get; set; }
        public string Last { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Email { get; set; }
    }

    public class PaymentProfile
    {
        public long Id { get; set; }
        public long CustomerId { get; set; }
        public string PaymentType { get; set; } //Bank or Card
        public string CardType { get; set; }    //Visa, MC, Diners, etc
        public string LastFour { get; set; }
        public DateTime AddedDate { get; set; }
        public DateTime ExpirationDate { get; set; }
    }

    public class Transaction
    {
        public long Id { get; set; }
        public long CustomerId { get; set; }
        public long PaymentProfileId { get; set; }
        public DateTime ProcessingDate {get;set;}
        public decimal Amount { get; set; }
        public bool Accepted { get; set; }    
    }

Rather than write code in your UI (controller classes) that interacts with your database or Authorize.Net and the database, you should separate it into other classes. I’ve added a created a ‘Services’ folder and 3 service classes to my project. For this sample we’ll write out the Services/CustomerProfileService class with basic CRUD functions

Next I added the following empty Web API controllers to my Controller folder.

  • PaymentProfileController
  • CustomerProfileController
  • TransactionController

To add the controllers you would right click your Controller folder, then click ‘Add new controller’, then select ‘Web API 2 Controller – Empty’, and click ‘Add’.

Now let’s create some REST functions in our Api controllers. Here is the code for the CustomerProfileContoller:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Threading.Tasks;
using PaymentProcessorApi.Models;
using PaymentProcessorApi.Services;

namespace PaymentProcessorApi.Controllers
{
     
    public class CustomerProfileController : ApiController
    {
        private CustomerProfileService _svc;
        public CustomerProfileController()
        {
            //in real app I would use IOC injection
            _svc = new CustomerProfileService();
        }

        public List Get()
        {
            return _svc.Get();
        }

        public CustomerProfile Get(long id)
        {
            CustomerProfile c = _svc.Get(id);
            if (c == null)
            {
                throw new HttpResponseException(HttpStatusCode.NotFound);
            }
            return c;
        }

        [HttpPost]
        public async Task Post(CustomerProfile customer)
        {
            try
            {
                _svc.Insert(customer);
            }
            catch (Exception ex)
            {
                 return BadRequest("Failed to insert.");
            }
            return Ok();
        }

        [HttpPut]
        public async Task Put(CustomerProfile customer)
        {
            try
            {
                _svc.Update(customer);
            }
            catch (Exception ex)
            {
                return BadRequest("Failed to update.");
            }
            return Ok();
        }

        [HttpDelete]
        public async Task Delete(CustomerProfile customer)
        {
            try
            {
                _svc.Delete(customer.Id);
            }
            catch (Exception ex)
            {
                return BadRequest("Failed to delete.");
            }
            return Ok();
        }
    }
}

If you run the application now in debug, you can navigate to your CustomerProfile controller at http://localhost:%5Byour port here]/api/CustomerProfile and since it is a GET, it performs the default GET action in your controller, which gets all of the customers, and it displays them in your browser. If you wanted to add a 1, 2, or 3 after the last slash in the url, it will display the customer profile for that customer.

Get with a browser

To test the Web API’s other functionality from a client, I’ve setup Postman in Chrome. Postman allows us simulate a client that makes requests and we can pass values in the body or header. If you don’t have Postman, you can google it and install it. It is free and is a chrome plug in. Once you have it installed:

  1. Run your application locally in debug.
  2. Open a new tab in your browser while it is running
  3. Click the Apps button near the top of your browser window.
  4. Select Postman – REST Client

AppsButton

In this screenshot, you can see that I’m calling the Get action of the CustomerProfileController, which returns all of the customers. Keep in mind we are not securing this controller at all at this time.

Get_postman

So let’s secure the controller by adding the [Authorize] attribute to the CustomerProfileController.

Require Authorization on the controller

 

Now if you run the same GET request, it will fail with a 401 Unauthorized error.

 

Get Fails Without Token

 

We now must login and get a token, then we can pass that token along with our requests. To login, change the request type to ‘POST’, and set the following parameters:

grant_type = password, username = [your user name], password = [your password], and click ‘Send’. If everything works, you will get an access token back. In the image below, I’ve received a bearer token that is valid for 14 days.

Postman To Get Token

Now we’re getting somewhere. So we have a token and our controller has been secured to authorized users. I’ve logged in so I’m authorized. I just need to make requests that include the bearer token so I can prove that I’m authorized. Here is how we do that.

In the Header we add:

Authorization = Bearer [paste in your token from previous request]

Now set the url to the /api/CustomerProfile action and set the request type to GET, and click the send button.  It works!!! We’ve proved our identity because we used our bearer token, so the response is successful and contains the customer profile.

Getting With Token Works

 

 

Here is a PUT call to update a customer profile. It includes the bearer token in the header just as the previous request did, so it is allows to update the customer.

Put with token A few details about how things work

When our application starts, there is a Startup.cs file that is run. You can find it in your applications root. It is a partial class, and the other part is in the App_Start folder’s Startup.Auth.cs file. Checkout the ConfigureAuth(IAppBuilder app) function to see how the tokens are setup.

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.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 = ""
            //});
        }

Notice the ‘AllowInsecureHttp = true’ line. When you publish your application you need to set that false in order to require SSL for all exchanges. Without SSL on your site, your tokens are sent as plain text. They can be stolen and used by imposters, and it almost the equivelant of using a login page that doesn’t have SSL. You can also set the timeout length for tokens. By default it is set to 14 days.

We’ve successfully created a new web api application that uses OAuth. We’ve created a user account, and logged in as our user. We’ve then accessed our secured controller actions by passing a bearer token in the header of our requests.

 

If you would like the sample application source code, it is available here: OAuthSampleApplication

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s