Simple OAuth Server: Implementing a Simple OAuth Server with Katana OAuth Authorization Server Components (Part 1)

In my previous post, I emphasized a few important facts on my journey of building an OAuth authorization server. As great people say: "Talk is cheap. Show me the code." It is exactly what I'm trying to do in this blog post. Also, this post is the first one in the "Simple OAuth Server" series.
1 April 2014
11 minutes read

Related Posts

In my previous post, I emphasized a few important facts on my journey of building an OAuth authorization server. As great people say: "Talk is cheap. Show me the code." It is exactly what I'm trying to do in this blog post. Also, this post is the first one in the "Simple OAuth Server" series.

What are We Trying to Solve Here?

What we want to achieve at the end of the next two blog posts is actually very doable. We want to have a console application where we handle calls to our protected web service endpoints and access them in a delegated manner which means that the client will actually access the resources on behalf of a user (in other words, resource owner). However, we won't be accessing the web service with resource owner's credentials (username and password). Instead, we will use the credentials to obtain an access token through the resource owner credentials grant and use that token to access the resources from that point on. After this blog post, we will expend our needs and build on top of our existing solution with the upcoming posts. That's why this post will be a little bit detailed about how you could set up the project and we will only cover building the OAuth server part.

Building the Application Infrastructure

I'll start by creating the ASP.NET Web API application. As mentioned, our application will evolve over time with the upcoming posts. So, this post will only cover the minimum requirements. So, bare this in mind just in case. I used the provided project templates in Visual Studio 2013 to create the project. For this blog post content, we only need ASP.NET Web API components to create our project.

Screenshot 2014-03-31 11.19.58 

Screenshot 2014-03-31 11.22.19

At the time of writing this post, visual Studio 2013 had the old ASP.NET Web API bits and it's worth updating the package before we continue:

Screenshot 2014-03-31 11.26.09

The OAuth authorization server and the ASP.NET Web API endpoints will be hosted inside the same host in our application here. In your production application, you would probably don't want to do this but for our demo purposes, this will be simpler.

Now we are ready to build on top of the project template. First thing we need is a membership storage system. Nothing would be better than new ASP.NET Identity components. I will use the official Entity Framework port of the ASP.NET Identity for our application here. However, you are free to choose your own data storage engine. Scott Allen has a great blog post about the extensibility of ASP.NET Identity and he listed available open source projects which provide additional storage options for ASP.NET Identity such as AspNet.Identity.RavenDB.

Screenshot 2014-03-31 11.36.12

There are two more packages that you need to install. One of them is Microsoft.AspNet.Identity.Owin. This package provides several useful extensions you will use while working with ASP.NET Identity on top of OWIN. The other one is Microsoft.Owin.Host.SystemWeb package which enables OWIN-based applications to run on IIS using the ASP.NET request pipeline.

The packages we just installed (Microsoft.AspNet.Identity.Owin) also brought down some other packages as its dependencies. One of those dependency packages is Microsoft.Owin.Security.OAuth and this is the core package that includes the components to support any standard OAuth 2.0 authentication workflow. Just wanted to highlight this fact as this is an important part of the project.

I will create the Entity Framework DbContext which will hold membership and OAuth client data. ASP.NET Identity Entity Framework package already has the DbContext implementation for the membership storage and our context class will be derived from that.

public class OAuthDbContext : IdentityDbContext
{
    public OAuthDbContext()
        : base("OAuthDbContext")
    {
    }

    public DbSet<Client> Clients { get; set; }
}

OAuthDbContext class is derived from IdentityDbContext class as you see. Also notice that we have another DbSet property for clients. That will represent the information of the clients. The Client class is a shown below:

public class Client
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string ClientSecretHash { get; set; }
    public OAuthGrant AllowedGrant { get; set; }

    public DateTimeOffset CreatedOn { get; set; }
}

This is the minimum that we need from the client to register in our authorization server. For certain grants, the client doesn't need to have a secret but for "Resource Owner Password Credentials Grant", it's mandatory. The client is also allowed for only one grant, that's all. This is not inside the OAuth 2.0 specification but it's the recommended approach. OAuthGrant is an enum and has the following values:

public enum OAuthGrant
{
    Code = 1,
    Implicit = 2,
    ResourceOwner = 3,
    Client = 4
}

These are all we need for now and we are ready to create the database. I will use Entity Framework Migrations feature to stand up the database and seed some data for demo purposes. As a one time process, I need to enable migrations first by running the "Enable-Migrations" command from the Package Manager Console.

Screenshot 2014-03-31 14.39.34

I will run the another command to add a migration code to reflect my context to a database schema: Add-Migration:

Screenshot 2014-03-31 14.41.44

Enable-Migration command created an internal class called Configuration and it contains a Seed method. I can use that seed method to inject some data during the database creation process:

protected override void Seed(SimpleOAuthSample.Models.OAuthDbContext context)
{
    context.Clients.AddOrUpdate(
        client => client.Name,
        new Client
        {
            Id = "42ff5dad3c274c97a3a7c3d44b67bb42",
            Name = "Demo Resource Owner Password Credentials Grant Client",
            ClientSecretHash = new PasswordHasher().HashPassword("client123456"),
            AllowedGrant = OAuthGrant.ResourceOwner,
            CreatedOn = DateTimeOffset.UtcNow
        });

    context.Users.AddOrUpdate(
        user => user.UserName,
        new IdentityUser("Tugberk")
        {
            Id = Guid.NewGuid().ToString("N"),
            PasswordHash = new PasswordHasher().HashPassword("user123456"),
            SecurityStamp = Guid.NewGuid().ToString(),
            Email = "tugberk@example.com",
            EmailConfirmed = true
        });
}

Now, I will use the Update-Database command to create my database:

Screenshot 2014-03-31 17.04.38

This command just created the database with the seed data on my SQL Express:

image

We will interact with our database mostly through the UserManager class which ASP.NET Identity core library provides. However, we will still use the OAuthDbContext directly. To use those classes efficiently, we need to write some setup code. I'll do this inside the OWIN Startup class:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.CreatePerOwinContext<OAuthDbContext>(() => new OAuthDbContext());
        app.CreatePerOwinContext<UserManager<IdentityUser>>(CreateManager);
    }

    private static UserManager<IdentityUser> CreateManager(
        IdentityFactoryOptions<UserManager<IdentityUser>> options,
        IOwinContext context)
    {
        var userStore =
            new UserStore<IdentityUser>(context.Get<OAuthDbContext>());

        var manager =
            new UserManager<IdentityUser>(userStore);

        return manager;
    }
}

This is the minimum code that we can write to use the UserManager class inside our OWIN components efficiently. Although I'm not fan of this approach, I chose to do it this way since doing it in my way would complicate the post.

OAuth Authorization Server Application with Katana OAuthAuthorizationServerMiddleware

Here we come to the real meat of the post. I will now set up the OAuth 2.0 token endpoint to support Resource Owner Password Credentials Grant by using the OAuthAuthorizationServerMiddleware which comes with the Microsoft.Owin.Security.OAuth library. There is a shorthand extension method on IAppBuilder to use this middleware: UseOAuthAuthorizationServer. I will use this extension method to configure my OAuth 2.0 endpoints through the Configuration method of my Startup class:

public void Configuration(IAppBuilder app)
{
    //... 
	
    app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
    {
        TokenEndpointPath = new PathString("/oauth/token"),
        Provider = new MyOAuthAuthorizationServerProvider(),
        AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
#if DEBUG
        AllowInsecureHttp = true,
#endif
    });
}

I'm passing an instance of OAuthAuthorizationServerOptions here and setting a few of its properties. Everything is pretty much self explanatory except of Provider property. I'm setting an implementation of IOAuthAuthorizationServerProvider to Provider property to handle the request at the specific places. Fortunately, I didn't have to implement this interface from top to bottom as there is a default implementation of it (OAuthAuthorizationServerProvider) and I just needed to override the methods that I needed.

Spare some time to read the documentation of the OAuthAuthorizationServerProvider's methods. Those are pretty detailed and should give you a great head start.

public class MyOAuthAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    public override async Task ValidateClientAuthentication(
        OAuthValidateClientAuthenticationContext context)
    {
        string clientId;
        string clientSecret;

        if (context.TryGetBasicCredentials(out clientId, out clientSecret))
        {
            UserManager<IdentityUser> userManager = 
                context.OwinContext.GetUserManager<UserManager<IdentityUser>>();
            OAuthDbContext dbContext = 
                context.OwinContext.Get<OAuthDbContext>();

            try
            {
                Client client = await dbContext
                    .Clients
                    .FirstOrDefaultAsync(clientEntity => clientEntity.Id == clientId);

                if (client != null &&
                    userManager.PasswordHasher.VerifyHashedPassword(
                        client.ClientSecretHash, clientSecret) == PasswordVerificationResult.Success)
                {
                    // Client has been verified.
                    context.OwinContext.Set<Client>("oauth:client", client);
                    context.Validated(clientId);
                }
                else
                {
                    // Client could not be validated.
                    context.SetError("invalid_client", "Client credentials are invalid.");
                    context.Rejected();
                }
            }
            catch
            {
                // Could not get the client through the IClientManager implementation.
                context.SetError("server_error");
                context.Rejected();
            }
        }
        else
        {
            // The client credentials could not be retrieved.
            context.SetError(
                "invalid_client", 
                "Client credentials could not be retrieved through the Authorization header.");

            context.Rejected();
        }
    }

    public override async Task GrantResourceOwnerCredentials(
        OAuthGrantResourceOwnerCredentialsContext context)
    {
        Client client = context.OwinContext.Get<Client>("oauth:client");
        if (client.AllowedGrant == OAuthGrant.ResourceOwner)
        {
            // Client flow matches the requested flow. Continue...
            UserManager<IdentityUser> userManager = 
                context.OwinContext.GetUserManager<UserManager<IdentityUser>>();

            IdentityUser user;
            try
            {
                user = await userManager.FindAsync(context.UserName, context.Password);
            }
            catch
            {
                // Could not retrieve the user.
                context.SetError("server_error");
                context.Rejected();

                // Return here so that we don't process further. Not ideal but needed to be done here.
                return;
            }

            if (user != null)
            {
                try
                {
                    // User is found. Signal this by calling context.Validated
                    ClaimsIdentity identity = await userManager.CreateIdentityAsync(
                        user, 
                        DefaultAuthenticationTypes.ExternalBearer);

                    context.Validated(identity);
                }
                catch
                {
                    // The ClaimsIdentity could not be created by the UserManager.
                    context.SetError("server_error");
                    context.Rejected();
                }
            }
            else
            {
                // The resource owner credentials are invalid or resource owner does not exist.
                context.SetError(
                    "access_denied", 
                    "The resource owner credentials are invalid or resource owner does not exist.");

                context.Rejected();
            }
        }
        else
        {
            // Client is not allowed for the 'Resource Owner Password Credentials Grant'.
            context.SetError(
                "invalid_grant", 
                "Client is not allowed for the 'Resource Owner Password Credentials Grant'");

            context.Rejected();
        }
    }
}

Petty much all the methods you will implement, you will be given a context class and you can signal the validity of the request at any point by calling the Validated and Rejected method with their provided signatures. I implemented two methods above (ValidateClientAuthentication and GrantResourceOwnerCredentials) and I performed Validated and Rejected at several points as I have seen it fit.

An HTTP POST request made to "/oauth/token" endpoint with response_type parameter set to "password" will first arrive at the ValidateClientAuthentication method. This is the place where you should retrieve the client credentials and validate it. According to OAuth 2.0 specification, the client credentials can also be sent as request parameters. However, I don't think this is such a good idea comparing to sending the credentials through basic authentication. That's why I only tried to get it from the "Authorization" header. If the client credentials are valid, the request will continue. If not, it will not process further and the error response will be returned as described inside the OAuth 2.0 specification.

If the client credentials are valid and the "response_type" parameter is set to password, the request will arrive at the GrantResourceOwnerCredentials method. Inside this method there are three things we will essentials do:

  • Validate the client's allowed grant. I's check if it's set to ResourceOwner.
  • If the client's grant type is valid, validate the resource owner credentials.
  • If resource owner credentials are valid, generate a claims identity for the resource owner and pass it to the Validated method.

If all goes as expected, the middleware will issue the access token.

Calling the OAuth Token Endpoint and Getting the Access Token

Let's try out the pieces that we have built. As you see previously, I have seeded a sample client and a sample user when during the database creation process. I will use those information to generate a valid OAuth 2.0 "Resource Owner Password Credentials Grant" request.

Request:

POST http://localhost:53523/oauth/token HTTP/1.1
User-Agent: Fiddler
Content-Type: application/x-www-form-urlencoded
Authorization: Basic NDJmZjVkYWQzYzI3NGM5N2EzYTdjM2Q0NGI2N2JiNDI6Y2xpZW50MTIzNDU2
Host: localhost:53523
Content-Length: 56

grant_type=password&username=Tugberk&password=user123456

Response:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 550
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?RDpcRHJvcGJveFxBcHBzXFNhbXBsZXNcQXNwTmV0SWRlbnRpdHlTYW1wbGVzXFNpbXBsZU9BdXRoU2FtcGxlXFNpbXBsZU9BdXRoU2FtcGxlXG9hdXRoXHRva2Vu?=
X-Powered-By: ASP.NET
Date: Tue, 01 Apr 2014 13:56:32 GMT

{"access_token":"ydbP24rMOATt7TK3dBCjluD2F5LcLkoX8ud39X135x0a1LEvOgsPf0ekm4Lyu2a06Rv_Z105GRZT_NoclgTTf7Slt5_WNfe68zOUq22j6MqW4Fh__Abzjm6I8otDzxvCJpt5d73R-Um6GwTui3LDbcOk5bH2BZuQLTJsNLknbLPu_FdpgkYfBodUoyPiFhv5-gNBEsfp4gCZYfdKtlhaK0wtloZiIzH1_sNPhBt9FavSfThM5BeoWkz8PFxkv_cOsOhOIzK66nSx7B2XL7K9aLqPSJLxus2ud8GBZyteSeFi26L9oX9do7MyCL1nXa8D9DRWfcIXiQi1v19AwyhoupP3L-k89xOK6_NTSzYOVhSMG9Juz8VYHWGkJeYTmekmnVkCvQe7KMQ6PceeUFJnA88TkiHNhai0hV8j012OUxPpUN5zRPJOU81XywSkQ7oKE0UsX3hQamgFrXV9eA-TSwZd4Qr-P9w6a82OM66Te9E","token_type":"bearer","expires_in":1799}

We successfully retrieved the response and it contains the JSON response body which includes the access token in the format described inside the OAuth 2.0 specification.

Summary and What is Next

In this post, we have set up our authorization server and we have a working OAuth 2.0 token endpoint which only supports "Resource Owner Password Credentials Grant" for now. The code is available on GitHub if you are interested in. In the next post, we will create our web service and protect it using our authorization server. We will also see how we can call this web service successfully from a typical .NET application.

Resources