Prefer a video instead? Watch this quick video where Anthony takes on a quest to get through the Authorization Code Flow in a retro-style rpg game.
There are four grant types in OAuth 2.0, and, by the end of this blog, you will have a better understanding of one of the most commonly used types: the Authorization Code Grant Type (Auth Code).
There’s a particular flow, or path, to follow, and my goal in writing this post is to give you a good understanding of the flow forwards and backwards. Or rather, a good understanding of it backwards and forwards—because I’ll step through the Auth Code flow starting from the end.
Learning the flow backwards gives you a better idea of what problem we’re trying to solve rather than focusing in on each particular step without understanding why those steps are taken. The process is important, but knowing the problem and solution at the outset can help us understand why the particular process came about, and we’ll have a much stronger understanding of the flow because of it. So first we will look, in reverse order, at the steps that might immediately lead to the desired outcome.
When to Use the Authorization Code Flow
Before we get into our example, here are a 4 things to look for when deciding whether to use the Auth Code Flow:
If you can use it, you should. The Auth Code flow is what the spec was designed around. The other flows are essentially optimizations or shortcuts we can make, depending on different assumptions or acceptable risk factors.
If time efficiency (quick response times for the end user) is a high concern, look at the other flows. Other flows require fewer round trips or calls to the various roles and can therefore save on time.
If network bandwidth or stability is a concern, look at other flows. Similar to the reasoning above in 2, if you need to keep the network calls as low as possible, other flows are more suitable.
If you want the best possible flow for security, choose Auth Code. The Auth Code flow provides a complete buffer layer when implemented properly, and with a trusted authorization server serving as the buffer layer, maximum security OAuth has to offer is ensured.
Example Problem and Solution
Okay, so let’s look at our problem. A resource owner has a protected resource but wants to give some kind of access to a client. The desired outcome, then, is for the client to have access to a protected resource where that access was granted by the resource owner.
For example, say you’re creating a new account on a site and don’t want to have to enter all of your basic information for the billionth time online. The new site might offer the ability to pull this information from your social media account and populate it for you. But some of that basic information is protected by a login, so you have to first grant just enough access to the new site to pull the protected information—and no more than is necessary—from your social media account. Therein lies the problem and what OAuth 2.0 is designed to do in a secure way.
(You might be asking: Why wouldn’t you just give the new site your username and password so they can log in and pull the information? Because that’s how your fifth attempt at a 15 character with a number, special character and capital letter password can become a member of the Pwnd Passwords list. You want to give the new site just enough access to pull the basic information without exposing your login and password info.)
Now that we have our problem and desired solution in hand, let’s start working our way backwards.
The Flow, Understood Backwards
If you read my blog on the abstract flow, the Auth Code follows it closely. That’s because it’s the intended use process to follow for OAuth 2.0. The other grant types have some assumptions that are made in order to shorten the steps or skip ones that aren’t viable for the situation.
The resource (in this example, your basic information) is stored securely with a resource server. The resource server’s job is to protect the resource from those not authorized to it. We could solve this by defining something that, when presented, shows that authorization has been appropriately granted, like a token encoded with a special message that specifies who has access and if the access is limited or scoped.
The resource server (the server holding the protected resource, in this example, the social media provider) only accepts access tokens that it can successfully verify. And, in order to get an access token, we must provide some way of proving that we’ve received authorization. The access token is the key to the safe, and we don’t want to hand out the key to anyone. So, now, we need to verify authorization has been granted to a person (or identity) before giving away the access token.
We could ask the client if they received authorization to access the resource, but this leaves it open for a bad actor to pretend they received authorization and get an access token. What would be better is if we could directly ask the resource owner if they authorize. We’ll want to make sure that we’re actually talking to the resource owner, so we’ll have them authenticate as well. Since we can’t talk to the client and resource owner simultaneously, we’ll give the resource owner something to serve as proof of their authorization: this is the authorization code.
Now we have something for the client to take to the authorization server to prove that the resource owner gave authorization and get an access token in return. Then the client can take the access token to the resource server to show they’ve been granted authorization and that it’s been verified by a trusted third party.
Authorization Code Flow, Understood Forwards
Here’s a step-by-step outline of the flow as seen from the other direction:
1. The resource owner (you) wants to share something protected (your basic information) with the client (the new website), so the resource owner goes to the Authorize Endpoint:
a. The resource owner authenticates (this spec does not prescribe how to do that)
b. The resource owner sends an authorization request to the authorize endpoint.
c. The authorize endpoint returns an authorization code.
2. The resource owner returns to the client with the authorization code.
3. The client sends a request for an access token to the token endpoint with the authorization code.
4. The token endpoint verifies the authorization code and returns an access token to the client.
5. The client requests access from the resource server with the access token.
6. The resource server returns the resource to the client.
Now, let’s take a closer look at step 1b. Why all the rigamarole with codes; why not just request a token instead? The answer, not surprisingly, has to do with security. The more hands on the token, the greater the risk of exposing it to bad actors. When the token is given to the client directly and not exposed to the resource owner and the user agent (browser), there’s less risk of it being exposed and therefore security is increased. (Keep in mind that the authorization server and the resource server have a working agreement on what the access token should look like and how to encode/decode it.)
The code, on the other hand, is an authorization grant generated by a third party rather than the resource owner themselves. The client redirects the resource owner to a third party, and then the third party redirects the resource owner back to client with the code. The client doesn’t have to authenticate the resource owner, adding an additional layer of protection to the process as it keeps the resource owner’s credentials with a trusted third party.
Additional OAuth 2.0 Grant Types
I hope this overview of the Authorization Code Grant Type has been helpful. In future posts, I will be describing other OAuth 2.0 grant types. In the meantime, if you need an authorization server, test out PingOne for Customers with a free trial!