top of page

OAuth 2.0 Explained in Simple Words - Part II

Updated: Mar 4, 2023

Want to know how OAuth 2.0 works? Read on and find it out.


This is a series of blogs exploring OAuth and OIDC:

OAuth 2.0 Explained in Simple Words - Part I: What and Why

OAuth 2.0 Explained in Simple Words - Part II: OAuth 2.0 Flows, Authorization Code Flow and Client Credentials Flow

OAuth 2.0 Explained in Simple Words - Part III: OAuth 2.0 Flows, PKCE Flow

OIDC Explained in Simple Words - Part I: OIDC as an OAuth 2.0 Enhancement

OIDC Explained in Simple Words - Part II: OIDC as an Modern SSO Standard



In this post, we continues from OAuth 2.0 Explained in Simple Words - Part I. We will be looking at different grant types in OAuth 2.0.


1. Client Registration

Before the client can interact with the Authorization Server, it needs to be registered in the Authorization Server to provide the following details:

  • Client ID

  • Client Secret

  • Redirect URI or Callback URL (could be multiple)

Client ID and Client Secret are similar to Username and Password. The former is used for Application and the latter is used for human user. By providing the client id and secret to the Authorization Server, it knows the client is a legitimate one to trigger the OAuth flow.


The Redirect URI is where the Authorization Server will do a http browser redirect to after the user authenticates in the Authorization Server.


2. OAuth 2.0 Grant Types

In part I, we talked about the OAuth 2.0 high level workflow. Now we will dive in with more details and one important part is to understand different grant types. Different grant types are just different workflows to get an Access Token and based on the scenario, we should pick the proper grant type.


Here is the list of Grant Types:

  • Authorization Code

  • Client Credentials

  • PKCE

  • Device Code

  • Refresh Token

  • Implicit (deprecated)

  • User Password (deprecated)

The first two, Authorization Code and Client Credentials, are the most often used. Authorization Code is used when an End User is involved (user-to-machine flow) while Client Credentials is used when NO End User is present (machine-to-machine flow).


The last two, Implicit and User Password are legacy flow and will be deprecated in the future.


In this post, we will go through the Authorization Code and Client Credentials workflow, as those two are crucial to understand OAuth 2.0.


3. Authorization Code Grant

The Authorization Code grant type is the most commonly used. There are mainly two parts in the process:

  1. User authenticates to Authorization server and Authorization Server returns Authorization Code to the Client (Browser based)

  2. Client uses Authorization Code to exchange an Access Token (No Browser)

Part one will be based on browser redirect and part two will be an Http Post where NO browser is involved.


Note, some Authorization Server (such as ForgeRock) supports step 1 - getting Authorization Code without Browser, meaning that Client can make REST call to its endpoint providing the same parameters as payload and get back the authorization code. This depends on the Authorization Server.


Step 1. User Accesses the Client.

User interacts with the Client app, which will trigger an Authorization Code grant workflow.


Step 2. Client Starts the Authorization Code

Remember the first part of the flow is browser-based, so it will start with an URL with some parameters.

https://authorization-server.com/oauth/authorize?response_type=code&client_id=test-client123&redirect_uri=https://oauth-app.com/callback&scope=read&state=PPKswuzDbVL06ankyPO6FoVwi1CdysR5

Notice that https://authorization-server.com/oauth/authorize is the Authorization Server address with the endpoint to start the flow. This is defined by the Authorization Server itself.

  • response_type=code - This tells the Authorization Server that the Client App is initializing the Authorization Code flow

  • client_id - The registered Client Name/ID from the Authorization Server

  • redirect_uri - The URI where Authorization Server will redirect to after authenticating the user

  • scope - One ore more strings (separated by space by default) indicating which permissions the application is requesting

  • state - A random string to keep track of current OAuth 2 flow transaction; the same value will be returned by the Authorization Server; this is to prevent CSRF attacks

Step 3. User Authentication

In this step, User needs to log in to the Authentication Server. OAuth 2.0 does NOT specify what kind of authentication method is required, so it all depends on the need. Sometimes a simple username/password will do, while other times, MFA (Multi-Factor Authentication) is needed.


After user is authenticated, Authorization Server might present a consent page to list out permission that the Client App is requesting to access. If user denies it, the flow will be terminated.


The consent page is optional and a lot of times, the Authorization Server can turn it off to indicate an 'implicit-consent'. This suits some use cases well.


Step 4. Authorization Server Returns the Authorization Code to the Client App

The return of the Authorization Code happens in the URL parameter and will be an Http browser redirect.

https://oauth-app.com/callback?code=2ummcKJvTt3ocgeI3RtdUOEWtZ6wMhmT&state=PPKswuzDbVL06ankyPO6FoVwi1CdysR5
  • code - This is the authorization code generated by the Authorization Server; it is usually short-lived (between 1-10 mins) and will be invalid once used

  • state - This will be the same value from the request; if the Client App sees a different value, the flow should be terminated


Step 5. Exchange Authorization Code for an Access Token

Once the Authorization Code is retrieved by the Client App, it will make an Http POST request to the corresponding Authorization Server endpoint to exchange the Authorization Code for an Access Token.


To send out the POST request, you can use CURL from command line or REST Client Tool like POSTMAN. The POST request will look like below:

POST /oauth/token HTTP/1.1
Host: authorization-server.com
 
grant_type=authorization_code
&code=2ummcKJvTt3ocgeI3RtdUOEWtZ6wMhmT
&redirect_uri=https://oauth-app.com/callback
&client_id=test-client123
&client_secret=xxxxxxxxxx
  • grant_type=authorization_code - This tells the Authorization Server that the Client app is using the Authorization Code flow; do NOT confuse with 'response_type=code' in step 2

  • code - The same as the value returned by the Authorization Server

  • redirect_uri - The same redirect URI that was used when requesting the code; this may not be required depending on the Authorization Server

  • client_id - The same client id that is used to request the code

  • client_secret - The secret with the registered Client to make sure it is a legitimate Client


Step 6 Authorization Server Returns an Access Token

All the parameters sent by the Client App will be verified by the Authorization Server and then it will send an Http response with the Access Token in the response body.

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
   "access_token":"eyJ0eXAiOiJKV1QiLCciOiJSUzI1NiIs...",
   "token_type":"Bearer",
   "expires_in":3599,
   "scope":"read",
   "refresh_token":"eyJ0eXAiOiJKV1QiAqdFSBzjqfTGAM4B4..."
}

Note a Refresh Token is included in the response as well. Access Token usually expires in a couple of hours and then the Client App can use the Refresh Token to call another Authorization Server endpoint get a new Access Token, without having the same End User to log in the Authorization Server again.



Step 7 Client App Access Resource Server with Access Token

Next, the Client App requests access to the protected resources on the Resource Server.


The Access Token is a bearer token, meaning it is self-contained. Any client possessing this token will be authenticated as long as the token itself is still valid.


The Access Token is put in the Http request Header with header name 'Authorization' and value 'Bearer ' (word 'Bearer' plus a space) inserted before the actual token. The word 'Bearer' is case-insensitive.

Authorization: Bearer eyJ0eXAiOiJKV1QiLCciOiJSUzI1NiIs...

Step 8 Resource Server Verifies the Access Token

Resource Server must always verify the Access Token before granting the Client App the access. Depending on the type of the Access Token, there are different ways to verify it.


One way is to send the Access Token back to the Authorization Server endpoint (introspection) and let it do the work. Another way is that if the Access Token is a JWT (a lot of times is), the Resource Server can decode the Access Token payload and verify expiration, scope, issuer as well as signature.


Token Introspection

By default, a Client can only introspect its own Access Token. Depending on the Authorization Server, a Client can introspect an Access Token issued to other Clients with some special scope values.

POST /oauth/introspect HTTP/1.1 
Host: authorization-server.com   

token=eyJ0eXAiOiJKV1QiLCciOiJSUzI1NiIs...

The Authorization Server will respond with the Access Token information.

{
    "active": true,
    "scope": "read",
    "client_id": "test-client123",
    "token_type": "Bearer",
    "exp": 1419356238
}

There are other endpoints as well such as revoking an Access Token, Jwks and .wellknown endpoints. We'll look more on this in OIDC.


Step 9 Resource Server Returns Resources to the Client App

Once the Access Token is verified, the Resource Server will send the requested resources back to the Client App and the flow is finished.



4. Client Credentials Grant

The client credentials grant is used when Client App is calling some API resources hosted by the Resource Server. This is considered a machine-to-machine (or server-to-server) call as opposed in the Authorization Code grant where user is involved.


Client Credentials Grant process is simpler than Authorization Code, where NO redirect is needed. Client App sends the request with Http POST to the Authorization Server and after verification, it will return the Access Token.



Step 1. Client Initializes the Client Credentials Flow

This will be a straight Http POST call to the Authorization Server.

POST /oauth/token HTTP/1.1
Host: authorization-server.com

grant_type=client_credentials&client_id=test-client123&client_secret=xxxxxxxxxx&scope=read

Notice that https://authorization-server.com/oauth/token is the Authorization Server address with the endpoint to start the flow. This is defined by the Authorization Server itself.

  • grant_type=client_credentials - This tells the Authorization Server that the Client app is initializing the Client Credentials flow

  • client_id - The same client id that is used to request the code

  • client_secret - The secret with the registered Client to make sure it is a legitimate Client

  • scope - One ore more strings (separated by space by default) indicating which permissions the application is requesting


Step 2. Return with Access Token

All the parameters sent by the Client App will be verified by the Authorization Server and then it will send an Http response with the Access Token in the response body.

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
   "access_token":"eyJ0eXAiOiJKV1QiLCJhbGSUzI1NiIs...",
   "token_type":"Bearer",
   "expires_in":3599,
   "scope":"read"
}

Note NO Refresh Token will be included in the Client Credentials flow.


The remaining steps are the same as in Authorization Code grant flow.


5. Sum Up

In this post, we talked about Grant Types in OAuth 2.0. Authorization Code and Client Credentials are the often used grant types. The former involves a User and the latter has NO User but rather machine-to-machine call. Then we talked the details of the two flows. Besides those two, there are other Grant Types - PKCE, Device Code and Refresh Token. The Implicit and User Password grant types are legacy and will be deprecated.


You can continue reading in the OAuth 2.0 Explained in Simple Words - Part III

128 views

Recent Posts

See All
bottom of page