A User's Guide to OAuth 2.0
I’ve been using OAuth 2 for a while now, and it seems every few months there’s a big kerfuffle because some provider or app has done OAuth 2 wrong, and left themselves open to exploitation. For the most part, I think these are mistakes where people just didn’t think, and there’s lots of room in the OAuth 2 spec to make bad mistakes. Really bad mistakes.
This is part one of a two-part guide to OAuth 2. Part one covers accessing an OAuth 2 service, part two will cover providing an OAuth 2 service.
In the flow
There are four ways to authenticate to an OAuth 2 API, and your provider may support one or more of them:
- Authorization Code
- Implicit
- Resource Owner Password
- Client Credentials
You can only use the first and the last. Even if your provider supports the others, don’t use them. The implicit grant is too easy to man-in-the-middle, and the third involves the user giving you their password, defeating the point of OAuth 2.
The client credentials grant is used for accessing APIs where your service or app needs to be authenticated but you aren’t accessing APIs related to the user. An example would be a search endpoint, or a public user profile url. It uses BASIC Auth to just pass your client credentials.
Authorization Code
The first flow is the one you’ll use almost all the time. I’ll explain it with an analogy.
You start at a new job and need to get a swipe card for the door. In order to get the swipe card, you go to security and get a form, which your manager has to sign to say which doors you can access, and when you can use it. Your manager signs to say you can have access to the front and back doors, between 8:00 and 18:00, but not on weekends. You take the form back to security, and security issue you a pass with an expiry in one year. They tell you if you come back within a month of it expiring, they can issue you with a new one without having to get the form signed again.
In this story, your app or website is you; the user is your manager; the authorization code is the form; security is the OAuth 2 service. Your app needs access to a user’s data, so the first step is to make an authorization request using your client credentials to the OAuth 2 service. Then you can direct the user to the service’s site, and they can authorize your app to access certain resources. You’ll get a redirect from the service to your website with an authorization code. Your app or site can then exchange the authorization code for an access token, and possibly a refresh token. The access token will only last for a certain while, and when it expires you can use the refresh token to get a new access token.
You should be aware that the authorization code and the access token are single use. If you have a failure of some kind, you’ll need to start the authorization process again.
In Detail
- Register your client with your OAuth 2 provider. You will be issued some credentials.
Obey the rules for your protection
The first thing you have to do is read the rules of your API provider. If you’re using a large provider like Google, Facebook, or Twitter, they will provide example code even whole toolkits and frameworks. Use them. If your provider recommends a library, use it. If you’re on desktop or mobile and there’s a system API to use instead, use it. Save yourself work and heartache.
On the flip side: don’t trust your provider. If you’re using a library or framework with a mobile app, check how it works. Make sure it’s keeping to best practice, because these things are not always well-maintained. Understand what it’s doing, when, and why.
HTTPS or Bust
All communications that you are involved in over the network must be encrypted. I can’t emphasize this enough, if you can’t do https, you can’t do oAuth 2, and really you shouldn’t be doing anything authenticated at all. Any provider worth their salt will only provide https endpoints, and will refuse to redirect to any non-https website. For the moment, this means no Squarespace, no GitHub Pages. SSL certificates can be bought for as little as $10 USD a year. Your hosting will be more than that.
Another part of this is you must use a ‘real’ https url, at your site or your providers, for all callbacks. Some providers give you the option of out-of-band (oob) callbacks, where rather than issuing a redirect to your website, the provider shows the user a code to copy. If you use that option, great. Otherwise always use https.
Access Tokens are Sacred
You need to protect your access tokens and refresh tokens, how you protect them depends on how your service works. If you have a website, do not store the access token in a cookie. Store it in a database on the server, and lock down your database. Make sure your database is safe from SQL injections which might steal the tokens. Use multiple database users with restricted permissions, so parts of the code doing, say, stats logging, don’t have access to the user tokens table.
If you are making a desktop or mobile client, do not store the token in plain text in a config file. Store it in the keychain on Mac and iOS, in an Android app encrypt the tokens with a RSA public key and store the matching private key in the keystore. On Windows encrypt it, on Linux, encrypt the password with a private key and keep the private key appropriately stored.
Client Credentials are Your Password
Would you leave the password to your server database in plain text in a config file for your mobile app? Would you put it in the JavaScript on your page?1. Then don’t do it with your client credentials. If someone else uses your client credentials then they can impersonate you to the service. With something like Twitter or Google which has API limits (which you could even be paying for), you really need to make sure you’re the only one using them. You probably won’t be able to encrypt your credentials, but at least put some effort in to obfuscate them, and keep an eye on their use. You might need to revoke them if someone else starts using them.
-
If your answer is yes, please stop doing anything with passwords or authentication. ↩