20

I've created a new ASP.NET Web API and things are working well. I'm at the point now where I want to secure the API.

I put the [Authorize] attribute above my base controller and it's working properly if I want to make API calls within the ASP.NET application itself.

However, I'm wondering, what's the best practice for an external client that wants to make API calls and get past the authorization? Also, keeping in mind I have custom authentication logic.

How should the client send over credentials? At what point do I process these credentials?

Adam Levitt
  • 10,316
  • 26
  • 84
  • 145

2 Answers2

21

How should I send the client credentials?

The default location to send authentication info, is the authorization header. You can use this for basic authentication but also for other types of authentication (JWT, Bearer, etc.).

Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

To add, for example, a basic authentication header to your request you could use the following code on your client:

WebRequest request = (HttpWebRequest)WebRequest.Create("https://yoururl");
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(System.Text.ASCIIEncoding.ASCII.GetBytes("user:password")));

At what point do I process these credentials?

I would write a DelegatingHandler and use it to resolve your 'principal'. You can then set it to the HttpContext.CurrentPrincipal to have it available wherever you need it within the scope of the request. The DelegatingHandler is called before your controllers as you can see in the image below, which makes it ideal for authentication logic.

enter image description here

I would do the same on the client (write a DelegatingHandler or ActionFilterAttribute) to add the authentication header on a default location. Note that DelegatingHandlers are part of the HTTP pipeline and ActionFilterAttributes belong to the MVC pipeline.

Last but not least I would recommend not to write your own custom authentication logic but stick with one off the default frameworks. This can be as easy as using basic authentication over HTTPS and as complicated as implementing OAuth. But I would stay away from do it yourself solutions.

I did like to also invite you to have a look at this answer I gave to a similair question.

Note: ASP.NET Web Api is REST based, so imho you don't want to keep session information at all.

Edit: For an example on how to implement a delegatinghandler that handle basic authentication see: basic http authentication in asp.net web api using message handlers.

Community
  • 1
  • 1
Jos Vinke
  • 2,704
  • 3
  • 26
  • 45
  • This was very helpful. One more question. What if I want to use OAuth. I'd need to create a separate OAuth service that creates some sort of token that the client would get first before making an API call, right? Is there a good example of this somewhere? I can't seem to find anything simple about security an ASP.NET Web API with Oauth. – Adam Levitt Nov 06 '13 at 01:16
  • If you want to set up a separate service to create tokens have a look at ThinkTectures IdentityServer. This should really help you out in this case: http://leastprivilege.com/2012/11/01/oauth2-in-thinktecture-identityserver-v2-resource-owner-password-flow/ If you want to set up the server yourself or implement it in your service have a look at [DotNetOpenAuth](https://www.nuget.org/packages/DotNetOpenAuth.Ultimate/). Then set up your own IAuthorizationServerHost. For some examples look here: https://github.com/ErikSchierboom/basicoauth2server.persistent. But be aware OAuth 2.0 is not 'simple'. – Jos Vinke Nov 06 '13 at 09:13
3

Basically you'll want to send the username and password encrypted over the net to your server application, then you can let your API generate a random session ID and keep it in a list (serverside) and send the ID back to the client. Now each time your client sends something to the server, include the ID he received in the packets and so the server can check it each time.

On client disconnection or fixed timeout you can remove the ID from the server list and ask the client to re-authenticate.

Chuk Ultima
  • 987
  • 1
  • 11
  • 21
  • Thanks for this help. If the client passes back a session ID, how do they pass this back to me? From where is all this information being sent? Http Header? Where do I write the code to process this? Is there any tutorial on this? – Adam Levitt Nov 05 '13 at 16:33
  • It all depends on how you built your application and which protocol you want to use. For example, if you just have a telnet application that sends and receives a string within a socketstream, you can put the ID as the first argument in the string message. The client just remembers the recieved ID by the server and uses it as a ticket to prove authentication until it disconnects. – Chuk Ultima Nov 05 '13 at 16:39
  • It's an ASP.NET Web API using all of the built in infrastructure of ASP.NET. Requests are accepted only via HTTP. – Adam Levitt Nov 05 '13 at 16:45
  • Avoid sending usernames and passwords over the wire for API. A shared secret and signing would be preferred. – Murray Foxcroft Apr 20 '16 at 10:48