I was surprised to learn this week that I wasn’t the only person in the world who was scared by OAuth. Given its popularity (Login with Facebook! Login with Google!) it seemed like it must be fairly well understood, but asking around I could find few people who said they felt comfortable with it, and no one able to describe it to me succinctly, especially without using the terms “resource owner” or “client”.
So I spent a couple of nights this week, reading the OAuth 1.0 and OAuth 2.0 RFCs. They’re a bit of a slog, so I’ve summarized the content below, along with less abstract descriptions of when you might want to use each of the five(!) different authorization methods.
Why use OAuth at all?
OAuth allows you to give a third party client fine-grained access to your data, as hosted on another site.
For example, say I wanted to use an online printing site to print my Facebook pictures. I’d like to restrict the site to seeing only my pictures on Facebook (not my contact information, or statuses), and to be able to revoke access in future. I’d also like to only have to change one set of credentials, if a site I grant access to is hacked, rather than the sites I’ve given access to.
OAuth 2.0 Naming Scheme
The naming scheme used for the OAuth 2.0 RFC is especially confusing to me, so for clarity I’m renaming a couple of things. These aren’t important unless you want to cross-reference the RFC.
- User: a resource owner, in the RFC
- Application: a client, in the RFC. The thing you’re trying to give access to your data to
- Service: in the RFC, this is split into a resource server and an authorization server, but I’ve never seen them be separate things. Where your data is stored, and where you authenticate
OAuth 2.0 Basic concepts
At a high level, OAuth 2.0 provides a way for an application to receive a token that functions as a username / password combination for a service, but that can be indepedently revoked by a user, and given limited scope.
In order to issue this token, a service must first be able to identify an application, so that a user can make an informed decision about how much scope, if any, they wish to grant.
Accordingly, before being issued any tokens, an application developer must first register their application with the service. This process is left very open by the OAuth 2.0 spec, requiring only:
- the endpoints to hit for the authorization methods below,
- enough detail for a user to identify the application, typically a name, logo, and potentially a URL, and
- whether or not the application can safely store secrets.
This last point, of secret storage, defines the type of OAuth authentorization an application is allowed to use. If the application is run on hardware the user controls, for example, a mobile app or native application, then it is considered public, since it cannot store secrets that the user cannot see. If the application can store these secrets, for example, a server-side application, it is considered confidential.
Typically, the OAuth 2.0 registration process requires that the application developer register as an application on the service, providing the above details. They are then issued with an ID, and in the case of confidential applications, a secret.
OAuth 2.0: Highly trusted mobile applications
The “resource owner password credentials” method is pretty simple — the user gives their username and password to the application, which then exchanges them for an OAuth token from the service.
Since this method involves the user giving their credentials to the application, it should only be used when the user trusts the application completely, for example, when the application is made by the service provider.
The RFC calls for this method of authorization to be avoided except where other authorization methods are not possible. This is presumably because there is no way for the user to determine if the application is using OAuth at all, nor to verify whether the scope being granted to the application is the scope they authorized.
OAuth 2.0: General mobile applications
The “implicit grant” method solves the problem of the user needing to provide their password to a potentially untrusted application.
With this method, the application asks the user to get a token for a particular application ID, typically by redirecting or opening the user’s browser to an authentication page for the service, with the application ID as a parameter.
The user can review the scope being granted and then enter their credentials, all while on the service’s site. The service then passes the token back to the user, who passes it to the application. This is also typically achieved using a redirect with the newly issued OAuth token as a parameter.
The RFC specifies that this method should only be used for public applications, such as mobile apps and native applications, or when very few round-trips are desired. This is because this method lacks any form of application authentication, allowing a malicious application to pretend to be a legitimate application, then steal the granted token from the location bar of an embedded browser. Additionally, the token could be stolen by other malicious applications running on the user’s hardware.
OAuth 2.0: Server-side applications
The “authorization code” method solves both the above-mentioned application authentication problem, and the “untrusted user platform” problem, but unfortunately only for server-side applications.
Unlike the other OAuth methods mentioned so far, it requires the application to have both an ID and a secret. Just as with the implicit grant, the user is redirected to a page on the service where they authenticate and evaluate the application’s requested scope. However, once this is complete, the user is issued an authorization code, rather than an OAuth token.
The user passes this code to the application, which then requests a real OAuth token from the server, signing the request with its secret. This guarantees that even if the authorization code is stolen by another application, it can only be converted to an OAuth token by the application itself.
This is the recommended authorization mechanism specified by the RFC, provided the application can indeed keep the secret secret.
OAuth 2.0: Friends of the service
The odd authorization method out in the OAuth 2.0 spec is the “client credentials grant”, which requires no authentication on the part of the user at all.
This method is intended for applications who can authenticate themselves with the service using their own credentials, and are then trusted to access a user’s data.
The most common scenario I can imagine for this is an application owned and run by the service, where users are shared – for example, Facebook’s developer site, in addition to the site itself.
OAuth 1.0: A trip into the past
Although not recommended for new applications, OAuth 1.0 is still in use in the wild, so I’ve included a description of it here for completeness’ sake.
The RFC for OAuth 1.0 is only informational, as the spec itself was originally published here. Full disclosure, I found it a bit confusing, and I’m still not totally sure if this is one of three possible authorization flows, similar to OAuth 2.0.
Like OAuth 2.0, OAuth 1.0 has its own confusing terminology, which I’m choosing to standardize to:
- client: application
- server: service
- resource owner: user
Also like OAuth 2.0, OAuth 1.0 requires that an application register with the service and be issued an ID and secret, before being granted any OAuth tokens.
In OAuth 1.0, the application starts the authorization process by asking the server for a set of temporary credentials with a given scope. It then passes these to the user, and asks that they authorize these credentials with the service. The user passes the temporary credentials to the service, authenticates, and reviews the scope they are requesting.
Once the user approves the request, they tell the application that they have done so. The application then goes to the service, and exchanges its temporary credentials for a real OAuth token.
This method has a number of problems: along with being a bit convoluted, and assuming that an application can successfully store a secret, it also requires the service to store state before the user has authorized anything. From a service’s perspective, this requires that temporary credentials be time-limited, a confusing scenario for a user to end up in.
It’s also worth noting that there are a number of other parameters that must be passed for OAuth 1.0, including timestamps, signatures, and nonces. I’ve decided not to include them here, for clarity.
OAuth: So you have a token
The OAuth spec doesn’t specify how an application should use an OAuth token once granted one, but typically an application just provides it as an authentication mechanism for a user.