5

If I was to implement a new server-to-server API, what authentication standards are available to make it as easy for others to consume?

Ideally the less I need to document about how the authentication works, the better (hence the standard), and its more likely that developers consuming the service can use a standard library.

Some restrictions though:

  • I can't guarantee that the API will be available on HTTPS, as it may be on a box hosting multiple websites (with 1 IP address).
  • It should block replay attacks... so if the request was captured by another node on the network, that same request can't be re-sent to the API.
  • Ideally you should just send the request and get back a response... so no need to contact the API first to get a one-time key (nonce)
  • The request should probably be signed by the sender in its entirety, to avoid man-in-the-middle type attacks.

I suspect an SSL type setup is a bit too complicated, as it seems most developers don't really know how to implement it properly.

With oAuth 1.0, it seems fairly simple:

http://provider.example.net/profile
    Authorization: OAuth realm="http://provider.example.net/",
    oauth_consumer_key="dpf43f3p2l4k3l03",
    oauth_signature_method="HMAC-SHA1",
    oauth_signature="IxyYZfG2BaKh8JyEGuHCOin%2F4bA%3D",
    oauth_timestamp="1191242096",
    oauth_token="",
    oauth_nonce="kllo9940pd9333jh",
    oauth_version="1.0"

But developers seem to be focusing on oAuth 2 now, with one possible solution being:

How does 2-legged oauth work in OAuth 2.0?

Which first requires you to call "/oauth/token" to get a token, but there doesn't seem to be much in the form of a specification on how this actually works (see replies):

http://www.ietf.org/mail-archive/web/oauth/current/msg07957.html

However there is some mention of using a MAC in oAuth 2, which might be useful... for example, do the Authorization once to get the MAC (with no login details), keep this semi indefinitely, and re-use for all subsequent requests:

http://blog.facilelogin.com/2013/01/oauth-20-bearer-token-profile-vs-mac.html

There is also an interesting discussion about HMAC, which kind of implies there isn't a standard on how this works either:

http://flascelles.wordpress.com/2010/01/04/standardize-hmac-oauth-restful-authentication-schemes/


Other notes:

Implementation, documentation and discussion for oAuth 1.0:

http://www.ietf.org/mail-archive/web/oauth/current/msg06218.html https://developers.google.com/accounts/docs/OAuth#GoogleAppsOAuth http://oauth.googlecode.com/svn/spec/ext/consumer_request/1.0/drafts/2/spec.html

Unfortunately the more I read about oAuth 2.0, the more I agree with Eran Hammer:

What is now offered is a blueprint for an authorisation protocol, "that is the enterprise way", providing a "whole new frontier to sell consulting services and integration solutions". http://en.wikipedia.org/wiki/OAuth

Community
  • 1
  • 1
Craig Francis
  • 1,855
  • 3
  • 22
  • 35
  • UCC/SAN certificates allow multiple hosts on a single IP. – ian Mar 24 '13 at 22:32
  • @iain Your right, but in my case its typically a server hosting domains from different clients (site owners), and they don't want to buy a single certificate together. There is also SNI (Server Name Indication), but that starts with IE7 or IE8 (not really tested), Firefox 2, Opera 8, Chrome 6, Safari 2.1, iOS 4.0, Android 3, and Windows Phone 7... so getting there. – Craig Francis Mar 25 '13 at 09:52

1 Answers1

9

Craig, great question. I am no expert, but have thought a lot about this, so a few thoughts.

Assuming we have to code against the lowest-common denominator, and using your requirement list (all 4 items) as my design seed, I would say the following:

  1. No SSL - Since you cannot guarantee SSL, you will have to go with a public/private key HMAC design. Let's just assume all traffic is over HTTP and is infinitely sniffable, which means you cannot transport any secure tokens or signing keys at any point over the wire to the caller, which means they need them already, which means a private signing key a-la something like what AWS does (or 2-legged OAuth or what I outlined in that article above).
  2. No Replay - Using a nonce to block replay doesn't require it be generated by the server, you can use any value here. The nonce just needs to be unique, needs to be included in your HMAC calculation (signature) and the server needs to remember it. For example, generate a UUID as a nonce on the client, sign the request, send it across to the server: ?sig=<a mess of chars>&args=<more stuff>&nonce=f81d4fae-7dec-11d0-a765-00a0c91e6bf6 -- the server will record f81d4fae-7dec-11d0-a765-00a0c91e6bf6 as processed and never allow it to be used again. You can probably safely expire these from the DB after a reasonable amount of time (month? depends on velocity/usage/etc). TIP: This is a perfect use-case for using Redis SETs and the SISMEMBER command.
  3. (see #2, combined answer)
  4. The request must be signed by the sender in its entirety. The key to understanding "what needs to get signed" is as simple as: anything you DON'T include in the HMAC (signature) calculation can be manipulated by a man-in-the-middle (MITM). Everything included in the sig is secured and CANNOT be changed without the sig check failing. This is why the OAuth specs (both of them) have pedantic rules about byte-ordering arguments, and how to append them and how to combine them, but you sign the entire request. Some APIs say something as simple as "take the entire query string, and sign it" -- but sometimes you get too much in that signature, like the domain name or endpoint that you might not want in there and need to change it in the future (or maybe you do, you're call).

Just so you know, the thing that makes secure API design instantly painful is the moment you don't require HTTPS for all communication. As soon as you do that, you have to turn to solutions like HMAC's/signing requests and nonce's. If your communication with the sever is secured over HTTPS and both can trust each other, life gets much better and you can do things like simple basic auth and just give the server an API_KEY with every request to identify who (or what) is making the request.

Hope that helps! It seems you've looked into this quite a bit already, so my apologies if you already knew all this and it didn't help.

Riyad Kalla
  • 10,604
  • 7
  • 53
  • 56
  • HMAC is the way I was leaning as well, so I'm glad we are on the same page... but my frustration is with oAuth 2 being presented as the solution for everything, but I really don't think it is (too complicated, and too generic to actually be implemented by everyone in exactly the same way)... I've +1 your answer, but still hopeful for a fully spec'd standard. – Craig Francis Mar 25 '13 at 10:12
  • Also, with the server recording the nonce (to avoid re-play), it could be deleted after a day, as long as you keep the UTC timestamp in there (as you also mention in your linked post).... but I'd suggest longer so you can have a log of whats happened on the server. – Craig Francis Mar 25 '13 at 10:21
  • @CraigFrancis You are absolutely right, OAuth 2 has turned into a monster and not such a clear spec (why one of the original authors left). I know you are looking for a spec-compliant answer, but keep in mind that not even AWS, one of the heaviest used APIs out there, follows any spec -- they did their own HMAC-based thing. I am sure it was because OAuth wasn't around back then (en-mass), but just pointing out that doing your own way, as long as it is clearly defined and easy to follow, isn't so bad. – Riyad Kalla Mar 25 '13 at 14:26