OAuth 2 and API Security discussion on Full Stack Radio podcast

Last week I was invited by Adam Wathan to appear on his Full Stack Radio podcast. We talked in depth about the OAuth 2 specification including all of the major grant types (when is best to use them, and some of the pitfalls), and then we talked about API security strategies for one of Adam's side projects. It was good geeky fun.

You can find the episode here - http://fullstackradio.com/episodes/4/.

OAuth and Single Page JavaScript Web-Apps

Earlier today I tweeted:

This kicked off a discussion across Twitter, Github issues and email about why I have such strong opinions about this.

It's simple, security. You just can't keep things that should be secret safe in client side code.

Let's assume that you've just made a shiny Angular/Ember/whatever single page web-app that gets all of it's data from an API that you've written via ajax calls. You've also elected to secure the API with OAuth and you're also securing the API endpoint with SSL (as the OAuth spec requires).

So because this is an app that you've written and it's talking to your backend you've decided that the "resource owner password credentials grant" (aka the "password grant") is the way that you're going to get an access token. The access token can then be used to authenticate API requests.

The web-app is going to make an ajax request to the API to sign the user in once you've captured their credentials (line breaks added for readability). This is how a valid OAuth 2 password grant access token request should look:

POST /auth HTTP/1.1
Host: api.example.com

grant_type=password
&client_id=webapp
&client_secret=52d14e22b9101
&username=alexbilbie
&password=whisky

The server will respond:

{
    "access_token": "DDSHs55zpG51Mtxnt6H8vwn5fVJ230dF",
    "refresh_token": "24QmIt2aV1ubaenB2D6G0se5pFRk4W05",
    "token_type": "Bearer",
    "expires": 1415741799
}

Already there are major problems with this.

First in the app's request we're sending the client ID and secret which the API uses to ensure the request is coming from a known source. As there is no backend to the web-app these will have to be stored in the front-end code and they can't be encrypted in code because you can't do crypto in JavaScript securely. So already we've got the problem that the only way of identifying the web-app - by using credentials - are already leaked in public code and will allow an attacker to attempt to make authenticated requests independent of the app. You can't use referrer headers to lock down requests either as they are easily faked. You can't store the credentials in an encrypted form in a cookie either because that cookie can be just grabbed by the attacker as easily as the client credentials that are baked into source code.

Moving on, in the response to the request the server has given us an access token which is used to authenticate requests to the API and a refresh token which is used to acquire a new access token when it expires.

First we've got the issue that the access token is now available to the attacker. He doesn't need anything else now to make requests to your API and go crazy grabbing all of the users' private data and performing any actions that the API allows. The server has got no way of knowing that it isn't the web-app making the requests.

Valid request from the web-app:

GET /resource/123 HTTP/1.1
Authorization: Bearer DDSHs55zpG51Mtxnt6H8vwn5fVJ230dF
Host: api.example.com

Valid request from an attacker:

GET /resource/123 HTTP/1.1
Authorization: Bearer DDSHs55zpG51Mtxnt6H8vwn5fVJ230dF
Host: api.example.com

Even if your API has short lived access tokens then the refresh token was also in the response to the browser so the attacker can use that to get a new access token when the original expires.

The simple story is here that you can't keep things safe in the front end. So don't.

Another scenario you might take when building your app and API is to implement the "implicit grant":

The implicit grant type is used to obtain access tokens (it does not support the issuance of refresh tokens) and is optimized for public clients known to operate a particular redirection URI. These clients are typically implemented in a browser using a scripting language such as JavaScript.
(https://tools.ietf.org/html/rfc6749#section-4.2)

This scenario is very similar to the flow that most people think of when they think of OAuth. That is, the user is redirected from the application they want to use to the identity provider, they sign-in, authorise the request and then are returned to the application. Then server side the application and the identity provider exchange some credentials and an authorisation code which was returned with the user and the end result is an access token.

The implicit grant is similar except instead of the user being returned to the application with an authorisation code, they arrive with an access token. Now if you're implementing a first party application which is talking to your API (so you implicitly trust it because you made it) then would be a crappy user experience because you're redirecting the user to other places when you should just ask the user for the username and password and avoid the "redirect dance". But anyway.

Because there is no token swapping server side there is now no need to worry about storing client credentials in front end code. But now you've just created a situation where (1) the API isn't authenticating the request for an access token (okay it is with a client ID and whitelisted redirect URI but I'm making a point here) and (2) you've just dished out an access token without any further verification that all parties involved are who they say they are. Congratulations!

For added pain the implicit grant doesn't support refresh tokens either so that access token is going to have a really long TTL or you're going to piss your users off by doing a redirect-dance whenever the token expires.

You could add some extra logic into your API so access tokens that were created with the implicit grant can only authenticate very specific read-only APIs but then you're reducing the usefulness of your application because it can't call all the endpoints available in the API.


I hope now you can see that there is a lot to consider when working with OAuth.

Please please please just avoid the implicit grant, it's a bag of hurt for everyone and it's just not worth implementing if you care even slightly about user experience and security.

So how can you use OAuth securely in single page web-apps?

It's simple; proxy all of your API calls via a thin server side component. This component (let's just call it a proxy from here on) will authenticate ajax requests from the user's session. The access and refresh tokens can be stored in an encrypted form in a cookie which only the proxy can decrypt. The application client credentials will also be hardcoded into the proxy so they're not publicly accessible either.

To authenticate the user in the first place the web-app will make a request to the proxy with just the user's credentials:

POST /ajax/auth HTTP/1.1
Host: example.com

username=alexbilbie
&password=whisky

The proxy will then add in the client credentials which only it knows and forward the request onto the API:

POST /auth HTTP/1.1
Host: api.example.com

grant_type=password
&client_id=webapp
&client_secret=52d14e22b9101
&username=alexbilbie
&password=whisky

The server will respond:

{
    "access_token": "DDSHs55zpG51Mtxnt6H8vwn5fVJ230dF",
    "refresh_token": "24QmIt2aV1ubaenB2D6G0se5pFRk4W05",
    "token_type": "Bearer",
    "expires": 1415741799
}

The proxy will encrypt the tokens in a cookie and return a success message to the user.

When the web-app makes a request to an API endpoint it will call the proxy instead of the API:

GET /ajax/resource/123 HTTP/1.1
Cookie: <encrypted cookie with tokens>
Host: example.com

The proxy will decrypt the cookie, add the Authorization header to the request and forward it on to the API:

GET /resource/123 HTTP/1.1
Authorization: Bearer DDSHs55zpG51Mtxnt6H8vwn5fVJ230dF
Host: api.example.com

The proxy will pass the response straight back to the browser.

With this setup there are no publicly visible or plain text client credentials or tokens which means that attackers won't be make faked requests to the API. Also because the browser is no longer communicating with the API directly you can remove it from the public Internet and lock down the firewall rules so that only requests coming from the web server directly will be allowed.

To protect an attacker just stealing the cookie you can use CSRF protection measures.


Making secure single page web-apps is possible, you just need to not get wrapped up in the "no backend" ideology and always remember that you can't trust the user.

Version 4 of league/oauth2-server is out!

After almost a year in development I've just tagged version 4.0.0 of league/oauth2-server.

Back in the summer I wrote about some of the problems I've faced during its development, but I've finally got there.

So what's new about v4?

First of all it's a complete rewrite from scratch. Theres some old saying about never rewriting software, but this is a component that to be used in a larger system, and good software practise involves sacrificing and upgrading modular components to improve the overall stack.

At the code level I've updated everything to pass around objects which are much easier to test and validate than arbitrary key value arrays. This will also mean that code documentation generated with phpDocumentor or ApiGen will be much more useful.

Because almost all of the underlying objects have interfaces you can swap in your own key generator and create your own tokens as well as creating your own grant types much more easily than before.

In addition I've made use of Symfony's Request class from symfony/http-foundation (which just about every framework uses) to parse and validate server requests which saves developers having to manually pass through request variables which was required in older versions.

The server now emits events which can be used to further integrate the library into your own application. For example the session.owner event is fired when a session has been allocated an owner - you might want to listen to this event to automatically add extra scopes (permissions) if the owner is an administrator. All of the events stuff is powered by the lovely league/events by Frank de Jonge.

All the code has been tested on the latest versions of PHP and HHVM too.

Finally, and probably most importantly there is some extensive documentation which can be found here - http://oauth2.thephpleague.com.

I'd like to thank everyone who has contributed to v4's development - especially Luca Degasperi and Jason Lewis and all the guys at the PHP League of Extraordinary Packages for their support, nagging and bug fixes.

Speed up Internet access in Vagrant boxes

This afternoon I've been playing with the Facebook API in a Vagrant box but requests to the API were immensely slow.

The following request would take 5.5221911907196s inside Vagrant:

But on my rMBP the same request took just 0.16792297363281s.

After a bit of Googling around I found that you can tell Virtualbox (through the Vagrantfile) to use the host as the DNS resolver:

After a quick vagrant reload the request took just 0.15842008590698s

Responding to reactions towards my job title

When people ask what I do for a living I say that I'm a software engineer. Nine times out of ten I will get the following reactions - "I'm not very good with computers" or "oo that sounds hard".

My comeback to the former is that I quiz them about what that person finds difficult when it comes to computers, and then I explain that they actually know more than they realise and it wouldn't take them long to adapt to new technology if they were put in that situation. For example discovering common features in a particular set of applications or websites may mean they also work in other applications and websites which means they can approach new things with some added confidence.

I discovered recently that there is actually a term for this joined-up experience: synoptic learning. Synoptic learning is the principle whereby experience, both through comfort and familiarity, with one part of a subject can help increase understanding with other parts because they're able to create connections to what they already know.

I consider myself a "power user" when it comes to desktop operating systems and smartphones; I'm quick at doing what I want to do and I'm quick to learn and adapt when things change. What irks me though is when applications redefine well-defined UI patterns or keyboard shortcuts so they result in unexpected actions. These slow me down, however I can generally adapt and adopt new muscle memory. But this is unlikely to be the case for non-technical users and can cause confusion, distrust and ultimately the feeling of being patronised by technology. It is important that we help our users to feel comfortable with our software by not breaking the "well understood" and guiding them in a non-patronising way through the unfamiliar.

Regarding the "oo that sounds hard" response I explain that fundamentally I just solve problems with computers. I find that this is usually interests people further and I describe how I tell the computer to evaluate an input and return an output in some form. A few times I've found people are actually really interested in how certain aspects of technology work, i.e. curiosities they've always had but have never had the opportunity to be explained. Sometimes these conversations have even gone into explaining boolean logic and if/else statements and loops.

In my experience, if you don't patronise non-technical people when you're explaining what we do as developers they are actually genuinely interested and have some respect for our craft; especially if they can relate what we've said to their own experiences.

Recently I did a guest lecture explaining "life as a software developer" to the 2nd and 3rd year computer science students at the University of Lincoln. A large number of slides were about the communication side of the job. I don't just sit all day staring at a computer screen; I communicate with my colleagues in the morning standup, on Hipchat, in meetings and over lunch and I communicate with myself through drawing on whiteboards and making todo lists and sketching out ideas.

But most importantly I communicate with those around me outside the workplace: my family and friends. I tell them what I'm up to because it helps build a support structure around me so that they understand some of the challenges I may face which explain why I'm knackered, or why I'm really pumped and fancy going to go to the pub for a pint and celebrating.

Regardless of how I anticipate someone reacting when I'm asked what I do, when I say I'm a software developer (or engineer; I use both words interchangeably) I always say it with pride knowing that through the work I'm doing right now I'm making others happy.