OAuth and JavaScript

A couple of days ago, Alex Bilbie posted OAuth and JavaScript about why you shouldn’t use OAuth APIs directly from JavaScript applications.

I may have missed the point — and that’s a distinct possibility — but I’m not sure I agree.

As far as I can tell, the security for web applications using OAuth 2 comes entirely from the redirect URL. There’s no way an attacker can get any tokens sent to them without either:

  1. being able to intercept and decrypt the HTTPS traffic, or
  2. being able to fiddle with the DNS of the client to get it to request the URL for the redirect from a web server under the attacker’s control (and have a valid HTTPS certificate for that domain)

In either of these situations, you probably have bigger problems.

In our pure JS web app world, we store the access token in the browser. Were an attacker to get hold of it, they’d be able to do anything the user has granted permission for the original client to do. Alex’s post suggests that you should use a thin API proxy hides away all the OAuth stuff, and the client then authenticates against that with an encrypted cookie. But in each case, the exposure is the same. If an attacker can get access to local storage, they can get access to the cookie. (Okay, not quite true. If there’s a JavaScript injection vulnerability in your web app, the cookie can still be protected with the HttpOnly flag. But the attacker can access all the data that comes back, so you’re not that much better off.)

The client secret is a red herring when it comes to web applications. The user can extract it, as can anyone else who wants to use it. It’s pointless in this context, and that’s presumably why the implicit grant exists. The implicit grant still has the protection of the redirect URL, and that’s enough.

Posted in Uncategorized | 4 Comments

4 Responses to “OAuth and JavaScript”

  1. Alex Bilbie says:

    I think you missed my point I’m afraid.

    My blog post isn’t about being tricked into being redirected to an attackers site; it’s about the client_id and client_secret which identify the client, and also the resulting access token being stored in client side code (or in memory client side).

    By proxying API calls the access token will never be revealed client side and so only your back end can authenticate correctly against the API.

  2. Alexander Dutton says:

    But the proxied secret in the cookie can still be used to achieve anything the original access token could have. What might someone be able to do with an access token in local storage that they wouldn’t be able to do with an encrypted cookie?

    There’s no (additional) harm in the client secret being public in this context. If you’re proxying the OAuth-protected resources to hide it, then all you’re doing is filling in that missing detail on requests made against the proxying service.

  3. Alex Bilbie says:

    The cookie is useless to a third party if you’re employing measures such as CSRF protection on the proxy.

    Fundamentally it’s about control. If I can view source and copy the client credentials there’s nothing stopping me building my own app that can authenticate against your OAuth service and then call the API.

    In addition your API doesn’t need to be exposed to a public network if calls are sent via (and upgraded with the decrypted access token) the proxy.

  4. Graham Klyne says:

    I’m with Alex B here.

    I think there’s also the nature of the token that the client gets vs what the server/proxy can get (I forget the proper OAuth2 names for these): following initial authentication the service gets an authentication token(?) via an HTTP redirect from the OAuth2 server, which can then be exchanged for a short-lived access token which can be passed to some service client – what the client sees is relatively short-lived (I think I’ve seen as little as a second), and IIRC has other restrictions on how it can be used. In order for the mediating service to get one of these tokens, it has to supply the OAuth2 server with an additional secret that is not ever passed to the (browser) client.

    IIRC, what Alex D describes is a different, less secure flow (“implicit flow”?) than the full OAuth2 protocol, and requires the client application to also see the user-supplied credentials. If you have a browser-based javascript app, there’s no way to “redirect” to it (that I know of), and a different flow has to be used — so, essentially, the “security of the redirect URL” aspect is missing in this case. Am I wrong?

Leave a Reply