Hacker News new | comments | show | ask | jobs | submit login

You should probably disregard this advice. Instead:

[Late addition:

* Do not use passwords as API authentication. The user of an API is a computer program, not a human. Issue single-purpose random credentials for API access.]

* Make sure that your API is accessible only over HTTPS; test the API endpoint to ensure requests aren't honored over unencrypted HTTP.

* Use the simplest API authentication mechanism that (a) works and (b) you understand. You should probably degrade the capabilities of your API before you try to adopt an authentication system that you don't completely, fully, absolutely grok.

This means, if you don't need delegation right away (for instance, if you don't have 3rd party applications making calls to your API on behalf of your users), don't bother with anything like OAuth.

Contrary to the implications in this article, HTTP Basic Auth is not less secure than OAuth if your endpoints all require HTTPS. If you allow HTTP calls to an API, you have bigger problems than your auth token scheme.

Semantic mismatches between API endpoints and web UI endpoints (ie, semantic differences between API auth and cookie-based authentication) are a classic, pervasive, hard- to- eradicate source of serious security flaws. Don't make things any more complicated than they need to be.

[Late edit: I didn't think I needed to make the first point, but I clearly did need to. Sorry.]

So let's say I have an iOS or Android app that needs to talk to my REST API. I have my user login in the app, which does Basic Auth over HTTPS.

Once they're authenticated, I generate a token and send it to them. They store it, and use that token from here on out (HTTPS only).

Perhaps I expire it after some time (hours or days, if I don't want my user to have to login all the time).

That's it? :D Seems like I'm missing something...

That sounds good. Think about how, e.g., Gmail lets you persist sessions on each device. They're doing a password auth over HTTPS and leaving a cookie with some session token.

That sounds very close to OAuth 2.

> Semantic mismatches between API endpoints and web UI endpoints (ie, semantic differences between API auth and cookie-based authentication) are a classic, pervasive, hard- to- eradicate source of serious security flaws. Don't make things any more complicated than they need to be.

Could you explain that one in more detail? I don't think I understand it.

You have one code path that authenticates web users through forms and sets cookies.

You have another code path that authenticates API callers.

You have code scattered through your whole application that makes authorization checks based on which user you're authenticated on.

Inconsistencies between the first two code paths often break that code.

Wow, I don't think I've ever seen tptacek gray in a thread about security. I don't know why, you are absolutely right.

One neat variant on this is how GitHub uses HTTP Basic auth to give you an OAuth token... http://developer.github.com/v3/#authentication

If you don't need delegation, there are a number of simple but secure methods: HTTPS + token via Basic auth seems quite popular.

What simple but secure methods are there where delegation is required? Is there something simpler than OAuth or AWS style signed HMAC?

The one true solution is client authenticated TLS. For the life of me I can't understand why 25 years later certificate management is still such a mess. 

We don't need some perfect universally recognized root trust system to get started. Why doesn't the sign up process for authenticated API access routinely include the issuance of a certificate signed by the API owner?

Unlike for interactive users there's no expectation that a customer will be accessing an API from some random computer where he might not have access to his certificate store. 

The user interface in browsers for client certificates is appalling.

The API support in client SSL libraries for managing multiple certificates, for applications with multiple API affiliations, is shaky.

I like TLS client authentication a lot, but it's hard to make it work.

I agree it's awful to use, but what I don't understand is why no one has bothered to improve the tools.

It's one of those areas where the underlying tool (either a library like openssl or NSS, or an OS feature like SSPI) could do the hard work in one place and make it simple for downstream libraries to wrap the functionality.

In other, somewhat analogous, domains that happened, but for whatever reason not in this case.

Look at the OpenSSL libraries for php regarding certificates. Its very close to unusable, you cannot get or set some pretty basic information like SANs.

Do you think there would be value in accepting HTTP requests and then automatically and immediately expiring every credential that ever gets passed over plain HTTP?

With an API, I think you're better off just not accepting HTTP connections to begin with. This is library design, so, principle of least astonishment. Break hard and fast.

Even if you use HTTPS, aren't you vulnerable to lazy devs who put the password in the URL?

If I use https://username:password@example.com/, doesn't that URL show up in server logs all over the internet?

Don't ever use passwords for API authentication. It's an API, not a browser. The users of an API are other programs, not people. Issue single-purpose random credentials.

I didn't think this was something I had to point out about API authentication, but apparently it is.

I have a stupid question: how do you do this with HTTP Basic auth?

Generate random long passwords.

By "don't ever use passwords" you mean, "don't let users set their own passwords," right?

Obviously, you're still using a password if you use HTTP Basic Auth.

You shouldn't ever use username/password pairs for API authentication. If the user ever changed their password, then their API calls would immediately fail!

This is one of many benefits of using multiple (revokable) API Keys.

No. The UA strips those and puts them in an Auth header.

Depends on the UA (curl?)

OK, so it'll either add an auth header or not know what to do and refuse to do anything. Either way the password is not sent in the request url

Actually, I mused have screwed up last night. The version of curl I have does support it and does put it into the Auth header.

  % curl --trace-ascii /dev/stdout http://jimktrains:password@news.ycombinator.com
  == Info: About to connect() to news.ycombinator.com port 80 (#0)
  == Info:   Trying == Info: connected
  == Info: Server auth using Basic with user 'jimktrains'
  => Send header, 223 bytes (0xdf)
  0000: GET / HTTP/1.1
  0010: Authorization: Basic amlta3RyYWluczpwYXNzd29yZA==
Some UAs however, do just drop it. Like IE (http://support.microsoft.com/kb/834489)

Even curl does the right thing for basic auth

Please correct me if I'm wrong. HTTPS will encrypt the URL, but the DNS lookup is in clear. So the "username:password@example.com" part will be sniffable/loggable.


That's incorrect. The URI library will parse the URL into a hostname, username, and password. Only the hostname is sent to the DNS server.

The username and password are sent in the "Authorization" HTTP header, which will be encrypted.

Shouldn't HTTP Digest still be preferred, so your server doesn't need to see the passwords?

That's not how HTTP Digest auth works, and you should never, ever be using "passwords" for API authentication.

Are you saying the server sees the password in HTTP Digest authentication?

How else would the server know what to check your response against? If you don't want to give the server a password, try SRP.

... but please don't use SRP for your API authentication.

Well, in this case (having gone back and actually checked the docs rather than relying on recollection roughly a decade old) you could store MD5(username:realm:password) rather than password, though that doesn't buy you all that much in a case like this where making the password a long, random string that's not reused is not only good practice but also easy and so likely to be general practice.

Stipulating all the other points you've made, exactly what is the purpose of hiding from a server a long random string generated by that server and useful only to that server?

Preventing someone else from getting that and using it on the server, especially if the service can rack up charges.

If you have the hash, you can log into the site (just not using the typical libraries), so it really doesn't add a lot of security. That's why I was wrong :-P

Yeah, I got there, just was confused about the digest thing.

I also wouldn't put too much value in a security article served on page using mixed HTTP and HTTPS. This shows a distinct lack of regard for and understanding of security.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | DMCA | Apply to YC | Contact