Token authentication and authorisation for a self-hosted ASP.NET Web API 2 REST service

djikay picture djikay · May 14, 2014 · Viewed 7.6k times · Source

I'm using VS2013 and Web API 2 to create a self-hosted (using OWIN), RESTful service over SSL using token authentication. Although I'm not a novice developer, this is my first time looking at ASP.NET technologies, so please keep that in mind.

I've got everything more-or-less working except for the authentication and authorisation parts. I fully understand the difference of authenticating a user (who is this user?) and authorising an already authenticated user to access a resource (can this user access this particular resource?).

A very simple overview of my auth process is as follows (makes some assumptions for brevity):

  1. An unknown client connects to the API, e.g. GET api/values.
  2. The server responds with a 401 and this response header: "WWW-Authenticate: Token".
  3. Upon seeing this, the unknown client knows to connect to a different API endpoint here: POST api/auth (routed to the Login function), supplying the username and password.
  4. The server will try to figure out if this is a valid user and can accept or reject the user depending on the validity of the credentials.
  5. (Rejected) The server returns an error status code (403?). End of process.
  6. (Accepted) The server creates a random token (e.g. a GUID) and stores it against the user record. Then it sends the token to the client.
  7. The now authenticated client reconnects to the API, GET api/values, and this time also supplies the token.
  8. The user returns the resource data to the client.
  9. ...
  10. The user can log out by connecting to the same API as he used to log in: POST api/auth (this time, his request will be routed to the Logout function). This will remove the token from the server and the client will also have to remove its own token.

As you can see, this is a relatively simple process, but I can't find any concrete and simple examples to understand how best to achieve this with a self-hosted Web API 2.

I don't need to register users or do any password/roles management, etc. and there is no external authentication. All valid users have the same rights to access the resources and they're already created in the system by a separate process over which I have no control (I can only read their credentials for validation). Most examples I found are talking about security frameworks that I don't need, so I've ruled out using any of the following: Basic Authentication, Windows Authentication, Forms Authentication, Individual Accounts, ASP.NET Membership/Identity, OAuth, Thinktecture or any other security framework.

I've read articles about authenticating in a message handler and others about authentication in a custom Authorize attribute filter, while others even suggest I should use the new (in Web API 2) IAuthenticateFilter attribute. This is very confusing. Can you please advise on a very simple way to achieve my auth objectives? Any specific code examples will be greatly appreciated, even if they're just skeleton implementation or pseudocode. I just need some ideas to get me started.

Answer

djikay picture djikay · May 16, 2014

After a lot of googling, I found this article on CodeProject: http://www.codeproject.com/Articles/630986/Cross-Platform-Authentication-With-ASP-NET-Web-API. While this is not Web API 2 or self-hosted, it has given me a number of ideas on how to proceed.

Someone also posted a comment to that CodeProject article referencing a NuGet package that may interest anyone looking for something similar: https://www.nuget.org/packages/WebApiTokenAuth. In my case, it is a bit much.

Finally, in addition to the authentication options mentioned in the question, there's also the option to write an OWIN middleware to do authentication if self-hosting using OWIN (as per the official MS recommendation). However, I plan to implement this particular form of token authentication with a message handler, as there's more support for this method available than for writing OWIN middleware.