What is OAuth 2.0 and where and why it is used

You have most likely come across OAuth 2.0 even if you didn’t know. The protocol is used for authorisation and can be difficult to understand with a lot of misleading information around. I hope to shed light on this protocol so you understand what it does and how it works.

Martin Hodges
13 min readFeb 2, 2024
OAuth 2.0 components

Solving the authorisation problem

Go back a decade or so and the Internet had a problem. People were having to log in to each and every web site separately. Remembering all the different passwords was difficult and keeping them secure even more so.

The services being offered started to integrate to other services. In order for them to do this, they started asking for your username and password to the other services so they could access your information and data.

This situation needed to be fixed and so OAuth 2.0 was created as the solution. Yes, there is an OAuth 1.0 as well as other solutions, such as SAML but in this article, I am talking about OAuth 2.0. In fact, in this article I will refer to OAuth 2.0 as simply OAuth. By the way, there will be another article on the subject of OIDC, which is closely related to OAuth but more on that later.

OAuth was developed to provide delegated authorisation. You are probably wondering ‘what does that mean?’

Put simply, it means that Service 1 could (with your permission) securely access your information in Service 2 without needing to be given your credentials to Service 1.

Problem solved.

Your food delivery service could now access your social media. Your professional network provider could now access your contacts. With OAuth all this authorisation remains under your control.

OAuth allows you to decide who has access to what and when. You don’t want them to have access any more, no problem. You want them to have access but not to your chat stream, no problem.

Authorising a service

This was so successful that you now see it almost everywhere. Each time you see a ‘Log in with Google’, ‘Log in with Facebook’, ‘ Log in with LinkedIn’ or any of the other similar links, you are starting an OAuth process. Although, strictly speaking these buttons are more to do with OIDC but they use OAuth under the surface.

As a fictitious example, let’s say you have a game MyBrillioGame and that it allows you to post your scores to your friends on the ChattyCat messaging platform. To do this, MyBrillioGame needs access to your account on ChattyCat.

You decide to post your scores to your friends and so MyBrillioGame passes you over to ChattyCat. ChattyCat gets you to log in (if you are not already) and then asks you if you are happy for MyBrillioGame to post messages on your behalf. You say yes (giving your consent) and ChattyCat gives MyBrillioGame an Access Token which it can use to post your scores without you having to do anything, even log in to ChattyCat.

It is important to understand that the Access Token does not allow MyBrillioGame to do anything else but post scores and, at any time, you can log in to ChattyCat and cancel the MyBrillioGame Access Token.

In this process you have provided delegated authorisation to MyBrillioGame to access your ChattyCat account.

By the way, like all authorisation, access can mean read, write, update or delete and more. You will be asked specifically to authorise the site (MyBrillioGames) for each type of access for each category of information or services it is requesting.

Terminology

One of the most confusing things about describing OAuth is the way we refer to all the components (eg: MyBrillioGame, ChattyCat and others).

Thankfully the OAuth standard gives us terms or names for these different parts.

Unfortunately, the names are not quite intuitive.

So let’s try and clear things up.

OAuth 2.0 terminology

In the diagram above you can see the OAuth 2.0 terms used for different parts of the solution.

Resource Owner

This is you. You are the person who owns the resource (eg: your messages and friends) that another site wants to access. So, from an authorisation perspective, Resource Owner makes sense.

Client

From an OAuth perspective, this is the service that wants to access your information or resources (eg: MyBrilllioGame). As such, it is the Client that is to access the service holding your resources.

Resource Server

This is the system that is securely holding your resources (eg: ChattyCat holding your messages and friends). These resources are precious to you and so the Resource Server should not give anything up unless the request comes from an authorised Client, ie, one with a valid Access Token.

Authorisation Server

In some ways, this is the key to making OAuth work. It is the system that knows about you. It is the system you log in to and so it is the system that authenticates you.

As you will see, it goes further than this. This is the system that will ask you if the Client can have access to your resources on the Resource Server. As such, it is known to OAuth as the Authorisation Server. It could be part of the Resource Server application itself (eg: MyBrillioGame) or a trusted third-party provider.

Abbreviations

Just to make it less clear, most descriptions of OAuth use the abbreviations:

  • Resource Owner: RO
  • Client
  • Resource Server: RS
  • Authorisation Server: AS

I’ll leave it to you to decide if you want to use these but in this article I will use the full name to help you understand what is happening.

How OAuth works

Now we have some understanding of what OAuth does, we need to look under the hood and see how it works.

There are several different ways (or flows) that OAuth can take.

  • Authorization Code Flow
  • Authorization Code Flow with Proof Key for Code Exchange (PKCE)
  • Implicit Flow
  • Client Credentials Flow
  • Resource Owner Password Flow

I will start with the Authorisation Code Flow as the rest are variations.

Authorisation Code Flow

Lets take our fictitious example to help explain what is happening.

  • You are the Resource Owner
  • MyBrilloGame is the Client
  • ChattyCat is the Resource Server

Let’s look at how it works. A lot of redirects happen with OAuth and so I have made it clear which user interface you are on, like this:

[UI: MyBrillioGame]

Request for access

[UI: MyBrillioGame]

You go to MyBrillioGame and click on the Post Scores button.

MyBrillioGame knows that it does not have authorisation to access ChattyCat on your behalf as it does not have an Access Token.

To get an Access Token, MyBrillioGame asks for one from the ChattyCat Authorisation Server. It does this by redirecting you to a specific ChattyCat URI along with some query parameters.

The request contains a number of fields:

  • response_type=code

The response_type defines the response expected from the request. In this case is is requesting a one-time use authorisation code (the authorisation code flow)

  • client_id=12345678

The client_id represents MyBrillioGame. ChattyCat does not let anyone ask for access, only those applications that have registered with it. ChattyCat would have issued this as part of the registration process of MyBrillioGames.

  • redirect_uri=https://mybrilliogame.com/blah

This is used later in the flow. Only certain URIs are allowed for security purposes.

  • scope=scope1+scope2+scope3

A scope is an arbitrary name that represents a particular access request. For example, post_message might allow posting messages whilst read_message might allow them to be read.

  • state=abcd12345

This is a random string that is added to the request. It is included in the response and the Client should check that it matches the request to ensure that no one is trying to inject a fake response.

[UI: ChattyCat Authorisation Server]

After being redirected to the ChattyCat Authorisation Server, the it determines that you have not logged in and redirects you to a login page on the Authorisation Server. You log in to ChattyCat.

Note that you are providing credentials to the ChattyCat service not to MyBrillioGame.

Once logged in, the original access request is then processed. ChattyCat Authorisation Server does the following:

  • Checks the Client is known to it (using the client_id)
  • Checks the redirect_uri matches acceptable URI patterns registered against the Client
  • Checks the requested scope list is valid for this Client

All being well, the Authorisation Server then presents the Resource Owner you) with the list of scopes being requested and asks for consent from you for MyBrillioGames to have that range of access.

Assuming you are happy with the scope being requested, you click the consent button.

The Authorisation Server now redirects you back to MyBrillioGames at the redirect_uri that was in the request. You can now probably see why the redirect_uri is validated. For security reasons you want to make sure you redirect back to the same place the request came from.

In this redirect, the Authorisation Server adds two parameters:

  • state=abcd12345
  • code=g0ZGZmDF d54NjVmOWIjNTk2NTk4ZTYdfsS

The state is the same value as was sent in the request. This allow MyBrillioGames to confirm that this is a response to its request.

The code is a one-time use code that is used in the next step.

[UI: MyBrillioGame]

Code/token exchange

Once MyBrillioGames gets the one-time code, it now exchanges it for an Access Token. It calls the ChattyCat authorisation Server one more time but this time it does this privately. Up until now all the values being exchanged are visible in the browser’s address bar or in its console. This time the exchange is hidden from the browser completely.

This is important as anyone who has the Access Token can pretend to be you and can access your resources. By making this a private connection, the Access Token remains out of sight and secure.

The request includes the following:

  • grant_type=authorization_code
  • code=g0ZGZmDFd54NjVmOWIjNTk2NTk4ZTYdfsS
  • redirect_uri=https:/blah.blah
  • client_id=12345678
  • client_secret=d54NjVmOWIjNTk2NTk4ZTYdfsS

The response is the Access Token. I will describe this later.

The MyBrillioGame server validates the Access Token and then, each time it posts scores to ChattyCat, it includes the Access Token in the header of the request. It needs to be added as an Authorized header as follows:

Authorization: Bearer <access token>

When theChattyCat resource server (ie: its API) receives a request, say to post a score, it checks the Access Token:

  1. If there is no Access Token, it should return 401
  2. If the Access Token is invalid, it may return 400, 401 or 403
  3. It the Access Token is valid* but does not include the required scope, it should return 403
  4. If the Access Token is valid and has the required scope, it should carry out the requested action, if other layers of security allow it to

* valid in this context means that the JWT is correctly constructed, the signature is valid (ie: the Access Token has not been tampered with), it has not expired, the issuer. was the verifier and more if required.

All being well, you now have your MyBrillioGame scores posted to your friends on ChattyCat.

Ok, so we have completed the Authorisation Code Flow but there are still a few outstanding questions. Let’s look at these now.

What is an Access Token?

An access token is a JSON Web Token (JWT), pronounced ‘jot’ for short. It is an encoded version of a JSON object and is signed to ensure that no one can tamper with it. In some cases the JWT can also be encrypted for additional security.

A JWT is a standard JSON object consisting of three parts:

  • A header
  • A payload
  • A signature

Header

This is a JSON Object Signing and Encryption (JOSE) header. It basically provides information on how the JWT is signed (and encrypted if applicable). Eg:

{
"alg": "HS256",
"typ": "JWT"
}

Payload

This is where the real work is done. The payload includes information about the validity of the JWT (eg: when it expires), who issued the JWT, the scopes it authorises and information about you (your claims). Eg:

{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}

This is a very basic example without any scopes!

Signature

The signature allows anyone using the JWT to prove it has not been tampered with on the way.

It is calculated by applying the algorithm in the header (with a suitable secret) to a string formed from the base 64 encoded value of the header + “.” + the base 64 encoded value of the body.

Putting it all together

So, to form the final JWT (which is just a string of letters and numbers), you use:

  • Encode the header into a base 64 string (h)
  • Encode the body into a base 64 string (b)
  • Calculate the signature (s)

The JWT then takes the form of (replacing the < > field with the values above):

<h>.<b>.<s>

For example, the values above creates this JWT:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

You can verify this by going to the jwt.io site and pasting in your JWT. It will decode it and show you the contents on the right side of the page.

Other types of flow

You should realise by now that the Access Token provides access to your resources and so it needs to be protected.

The Authorisation Code Flow ensures that the Access Token is kept securely and away from browsers. This reduces the number of attack methods that attackers can use (the attack plane), which is a good thing.

This flow assumes that the Client has a private channel back to the Authorisation Server but this may not always be available. For this reason, there are other flows:

  • Authorisation Code Flow with PKCE
  • Implicit Flow
  • Client Credential Flow
  • Resource Owner Password Credentials Flow

Authorisation Code Flow with PKCE

PKCE stands for Proof Key for Exchange and is pronounced pixie. This is where the client cannot secure the code to Access Token exchange, for example with a mobile device.

In this flow, the Client adds a hashed secret (code_challenge) to the initial request for access and then presents unhashed secret (code_verifier) again when asking for the Access Token. This ensures that no one can intercept the authorisation code and exchange it for an Access Token as they do not have the secret.

Note that this means that the Client does not need to present a Client ID and Secret.

Because of the increased level of security, this flow is sometimes used for Clients that would normally use the Authorisation Code Flow. If the extension is used then the Client should still use its credentials in additional to the PKCE code when retrieving the Access Token.

Implicit Flow/Implicit Grant Flow

In this case, the Client cannot store a Client ID and secret (eg: a Web App or Single Page Application). When it requests an Access Token, it does not receive an Authorisation Code to exchange but gets the Access Token directly.

Client Credential Flow

In cases where a Client is a system that owns the resource, there is no user involved. This is a system to system access.

In this case the Client simply requests an Access Token by providing its Client ID and Client Secret.

Resource Owner Password Credentials Flow

Similar to the Client Credential Flow, this flow uses a username and password of an actual user to obtain an Access Token.

As this involves the user providing their credentials to the Client, this is highly discouraged and should not be used.

Which flow to use

The flow to use will largely depend on what your Client application is. Remember, if it is running in a browser, anything is accessible to a malicious user, including code and data. This means it cannot store secrets, such as Client IDs and Client Secrets. This means it cannot follow the Authorisation Code Flow.

This shows us that the flow to use depends on the Client. Here are some broad principles:

  • Server-based client: Authorisation Code Flow (optionally with PKCE)
  • Web application/Single Page Application client: Authorisation Code Flow with PKCE or possibly Implicit Flow (not recommended)
  • Mobile application client: Authorisation Code Flow with PKCE
  • Server to Server: Client Credential Flow

Refresh Tokens and revocation

Whilst we have been talking about obtaining an Access Token, the process actually returns two tokens, an Access Token and a Refresh Token.

Whilst the Access Token provides the access to the resource by way of its scopes, the Refresh Token provides authorisation to get another Access Token (of the same scope).

You may be wondering why we need two tokens. It is all about revoking access.

Using the example I used earlier, let’s say you give MyBrillioGame access to your ChattyCat service. Latter you decide you need to revoke that access. May be MyBrilllioGame is sending too many scores, may be you no longer use MyBrillioGame or may be the Access Token has been stolen and someone is using your ChattyCat account without your permission.

If the Access Token has a long expiry, say days, weeks or longer, then you may have to wait a long time before the Access Token is no longer valid and access is no longer granted.

The alternative is to reduce the timeout, say to 15 minutes. The trouble is, you don’t want your Client having to go through all the redirects to get a new token every 15 minutes. What is more, if you have logged out of ChattyCat, you would then have to log back in.

The Refresh Token solves this. After the Access Token times out, the Client can directly ask for a replacement Access Token, offering the Refresh Token as authority to get one. It can do this without having to request access again.

Now, if you tell ChattyCat that you no longer want MyBrillioGame to access your account, you only need wait a maximum of 15 minutes. After this, when the Client requests a new Access Token, it is rejected and MyBillioGame no longer has access.

Note that even Refresh Tokens have a timeout but this is normally a long time.

Registration of clients

In the Authorisation Code Flow the Client needs to be registered with the Authorisation Server in order to receive its Client ID and its Client Secret.

This registration process may happen automatically or manually.

Third-party OAuth services

In most cases, the Authorisation Server is part of the same system as the Resource Server. This makes sense as the organisation securing your resources also secures your identity.

Some organisations, such as start-ups or small enterprises or even enterprises that do not want to manage the security of their user base, can use a third-party identity provider that provides an OAuth interface, such as Auth0, Okta, Google, Azure, AWS and more.

Most OAuth services have an auto-discover end point that allows the Client to quickly retrieve a list of other end points and public keys etc. This allows a Client to interact easily with different OAuth suppliers.

Summary

The aim of this article was to explain the OAuth 2.0 protocol. I explained where the need came from and how OAuth solves that need.

We looked at how Refresh Tokens protect Access Tokens by allowing sessions to be short and new Access Tokens to be obtained easily.

Finally, we looked the different flows supported by OAuth and looked at third-party identity suppliers.

If you found this article of interest, please give me a clap as that helps me identify what people find useful and what future articles I should write. If you have any suggestions, please add them in the comments section.

--

--