REST API authentication for web app and mobile app

maknz picture maknz · Feb 2, 2014 · Viewed 44.4k times · Source

I'm having some trouble deciding how to implement authentication for a RESTful API that will be secure for consumption by both a web app and a mobile app.

Firstly, I thought to investigate HTTP Basic Authentication over HTTPS as an option. It would work well for a mobile app, where the username and password could be stored in the OS keychain securely and couldn't be intercepted in transit since the request would be over HTTPS. It's also elegant for the API since it'll be completely stateless. The problem with this is for the web app. There won't be access to such a keychain for storing the username and password, so I would need to use a cookie or localStorage, but then I'm storing the user's private details in a readily accessible place.

After more research, I found a lot of talk about HMAC authentication. The problem I see with this approach is there needs to be a shared secret that only the client and server knows. How can I get this per-user secret to a particular user in the web app, unless I have an api/login endpoint which takes username/password and gives the secret back to store in a cookie? to use in future requests. This is introducing state to the API however.

To throw another spanner into the works, I'd like to be able to restrict the API to certain applications (or, to be able to block certain apps from using the API). I can't see how this would be possible with the web app being completely public.

I don't really want to implement OAuth. It's probably overkill for my needs.

I feel as though I might not be understanding HMAC fully, so I'd welcome an explanation and how I could implement it securely with a web app and a mobile app.

Update

I ended up using HTTP Basic Auth, however instead of providing the actual username and password every request, an endpoint was implemented to exchange the username and password for an access key which is then provided for every authenticated request. Eliminates the problem of storing the username and password in the browser, but of course you could still fish out the token if you had access to the machine and use it. In hindsight, I would probably have looked at OAuth further, but it's pretty complicated for beginners.

Answer

Jørn Wildt picture Jørn Wildt · Feb 6, 2014

You should use OAuth2. Here is how:

1) Mobile App

The mobile app store client credentials as you state yourself. It then uses "Resource Owner Password Credentials Grant" (see http://tools.ietf.org/html/rfc6749#section-4.3) to send those credentials. In turn it gets a (bearer) token it can use in the following requests.

2) Web site

The website uses "Authorization Code Grant" (see http://tools.ietf.org/html/rfc6749#section-4.1):

  1. Website sees unauthorized request and redirects browser to HTML-enabled autorization endpoint in the REST api.

  2. User authenticates with REST service

  3. REST site redirects user back to website with access token in URL.

  4. Website calls REST site and swaps access token to authorization token.

Here after the website uses the authorization token for accessing the REST service (on behalf of the end-user) - usually by including the token as a "bearer" token in the HTTP Authorization header.

It is not rocket science but it does take some time to understand completely.

3) Restricting API access for certain applications

In OAuth2 each client is issued a client ID and client secret (here "client" is your mobile app or website). The client must send these credentials when authorizing. Your REST service can use this to validate the calling client