Auth & identity
March 23, 2023
Author: Stytch Team
OAuth (which stands for open authorization) refers to a set of protocols that allow web apps to share information with each other on behalf of a user, without sharing any account credentials. In more technical terms, we can say that OAuth is a protocol that delegates access and permissions between APIs and applications in a safe and reliable exchange.
OAuth 2.0 is the most recent version of these protocols.
OAuth was jointly developed in 2006 by Twitter and Google. With near universal adoption of social media sites, developers realized that their applications would greatly benefit from letting users bring in their data from accounts like Facebook, Twitter, or Google.
You’re probably most familiar using OAuth with social accounts. If you’ve ever authorized an app to access the resources in your Gmail or Facebook account, you’ve used OAuth. Examples of these authorization prompts look like:
The beauty of OAuth is its ability to let users provide access to their accounts without exposing their login credentials, and to fine tune what exactly each app can or cannot access within the others’ resources. When you’re able to specify which actions another app can take with your GoogleDrive contents, you’re benefiting from OAuth.
There are four key roles involved in any OAuth transaction: the client, the resource owner, the resource server, and the authorization server. (If you’ve read our material on OIDC, these may seem familiar because OIDC was built on top of OAuth 2.0!)
This is the service that attempts to obtain access to the resource owner’s account or resources that are held on the resource server. This is the application seeking authorization, and is often also referred to as the application.
The resource owner is the user, application, site, or system that owns the resources the client is trying to access. This is the application granting authorization, and is often also referred to as the user.
The resource server is where the resource owner hosts its protected resources or accounts on behalf of the user, or resource owner.
The authorization server is the party that makes it possible to grant authorization between different apps or services without sharing credentials. They both verify the identity of the user and send the access tokens to the client on behalf of the resource server once access has been granted.
Now that we understand the main roles involved in an OAuth 2.0 transaction, let’s look at the basic flow. Note that there are a few different OAuth flows that vary by the grant type (see below), so for covering the basics today we’re just going to look at the most common – the authorization code flow.
Here’s how it works:
Now that we have the lay of the land, let’s look a little closer at each of these steps to understand what exactly each role is passing to each other, and how.
While the first step of a basic OAuth 2.0 generally begins with the client’s authorization request, it technically begins with client registration. To do this, they’ll need three main inputs: their application name, their application website, and a redirect URI where the resource server can redirect the user after access has been authorized. These registered URIs help prevent token stealing and other attacks.
Upon completing registration, the client receives two key pieces of information they’ll need for their authorization request:
The client ID is a public string that the resource server uses to identify the client.
The client secret is a private string that is used to verify the identity of the client with the resource server when they submit their access token in step 6.
Once registered, a client kicks off an OAuth 2.0 transaction when the client requests to access resources belonging to the resource owner.
This is most commonly done by actually creating a URL for the user to click on that redirects them to the authorization server. The application makes sure this URL has all the relevant information including the client_id, the scope, the authorization grant type, and a PKCE code, if they have one. Let’s look at what all of those parameters entail (except client ID, which we just learned):
The scope defines the exact resources to which the resource owner is granting the client access. So if for example you want to give Twitter access to your GooglePhotos, the scope parameter helps ensure that Twitter doesn’t also gain access to any other resources on your Google account.
The grant type refers to the method used to authorize the client on behalf of the resource server, and depends both on the grant type requested by the client and the capabilities of the resource server’s API.
There are generally three types of authorization grants, each with their own best use cases: authorization code, client credentials, and device code. (You may also hear some OAuth literature discuss implicit and password grant types, but these are considered legacy practices and not recommended today because of various security concerns).
The authorization code flow also has an extension called PKCE, or Proof Key for Code Exchange, that helps thwart cross site request forgery (CSRF) and authorization code injection attacks. In this system, the client creates a secret with each authorization request, which they then resubmit with the authorization code when requesting the access token. This helps ensure that if the authorization code is intercepted, attackers still won’t be able to gain authorization without that additional secret.
When the user clicks on this newly-minted link, they will be taken to a URL with an authorization request. This is the part of this transaction we’ve most likely seen before, something like, “This application [aka the client] would like to access resources on your account [aka the resource server]. Do you authorize this access?”
We’ll proceed with the rest of this flow on the assumption the user clicks “Yes”!
Once the user authorizes access, the authorization server will redirect them back to the client’s application, but to a URL that includes the authorization code. Note this is sent as an HTTP request from the authorization server to the user’s browser – there’s no direct communication with the client’s application.
Once they have their authorization code, the client requests the access token from the authorization server by making an HTTP POST request, which includes the authorization code, the grant type, the redirect URI, the client ID, client secret, and PKCE code verifier if they’re using it.
Access tokens are how the client is able to make API calls on behalf of the resource owner: they prove to the resource server that the client is authorized to do and access certain resources on that user’s behalf. Because they give authorization permission to whoever bears them, they are also sometimes called bearer tokens.
Access tokens can come in a variety of formats, but generally consist of an alphanumeric string that is randomly generated and then securely stored with the authorization server. Some authorization servers opt for self-encoded tokens, which encode all the necessary information within the code string itself, thereby eliminating the need of a server-side database.
Regardless of the token’s form, it is important in every case that they are kept confidential when in transit from the authorization server to the client, and from the client to the resource server. For that reason, access tokens can only be exchanged across HTTPS connections.
Upon receiving this HTTP post request, assuming all of the parameters are correct, the authorization server will issue an access token (and sometimes a refresh token), along with the token type and the expiration time.
With the access token in hand, the client can now request access directly from the resource server via an API call. This should be successful so long as the access token has not yet expired.
If the API request contains all the correct information, the resource server will grant the client access to the scoped resources.
And with that, we have a successful OAuth 2.0 transaction!
OAuth 1.0, released in 2007, was the initial result of Twitter and Google’s collaboration. It was largely based on two pre-existing protocols: Flickr’s authorization API (remember Flicker?) and Google’s AuthSub. After several years of developers using OAuth 1.0 out in the wild, a larger group of invested companies began discussing possible improvements. These companies included Facebook, Microsoft, Mozilla, and Yahoo!, (as well as the original collaborators Google and Twitter).
In 2012, five years after 1.0, OAuth 2.0 was released. It came with some major improvements:
In OAuth 1.0, there are only three roles, not four: the consumer (what we now call the client), the user (what we now call the resource owner), and the service provider (what we now call the resource server and the authorization server, collapsed into one).
Instead of bearer tokens, OAuth 1.0 uses cryptographic signatures, in which each access token has both a public and private string, with the private string being used to sign the authorization request. Because bearer tokens don’t require a cryptographic signing of every request, they’re viewed as a simpler, more elegant access token solution.
OAuth 1.0 originally had three flow types, but those were eventually collapsed into a single flow that was supposed to work for all use cases – web-based apps, desktop clients, and browserless apps. But as OAuth use scaled, it became clear that this “one-size-fits-all” approach actually resulted in clunky functionality and poor user experience. Hence the variety of grant types in OAuth 2.0, that allow more tailored flows for different use cases.
As originally implemented, OAuth 1.0 tokens were valid for a very long time, sometimes indefinitely or up to a year (yikes!). OAuth 2.0 replaced this system with very short-lived access tokens and the option to implement longer-lasting refresh tokens – a much better way of allowing minimally disruptive session refreshes without compromising on security.
Every person who’s online today divides their resources between upwards of dozens of applications. With so many of our individual and company resources increasingly stored on the cloud, interoperability and mutual access become all the more important. But with that increased interoperability comes great responsibility, and potential security risk. OAuth 2.0 is a crucial piece of cloud-based information access and sharing because it enables for secure, scoped, delegated access.
Additionally, OAuth 2.0 paved the way for OpenID Connect (OIDC), an authentication and authorization protocol that allows users authenticated in one place to gain access to resources in another (if you’ve ever used “social login,” or logged into another app with your Google, Facebook, or LinkedIn account – you’ve used OIDC!).
If you’re interested in how these products might help streamline your developer’s workload, feel free to explore our docs or talk to sales by clicking the links below.