In this post, we will be covering all OAuth 2.0 flows using GIFs that are simple and easier to understand. This post can be used as a cheat-sheet for future reference as well!
Note: Feel free to ⏩ skip to the flows directly if you are already aware of OAuth.
OAuth (Open Authorization) enables third-party websites or apps to access user's data without requiring them to share their credentials. It is a set of rules that makes access delegation possible. The user gets to authorize which resources an app can access and limits access accordingly.
Now that we know what OAuth is about, let us quickly cover the terminologies before we dive-in.
|Client 📦||The application that seeks access to resources. Usually the third-party.|
|Resource Owner 👤||The user who owns the resources. It can also be a machine 🤖 (E.g. Enterprise scenarios).|
|Resource 🖼||Could be images, data exposed via APIs, and so on.|
|Resource Server 📚||Server that hosts protected resources. Usually, an API server that serves resources if a proper token is furnished.|
|Authorization Server 🛡||Server responsible for authorizing the client and issuing access tokens.|
|User-Agent 🌐||The browser or mobile application through which the resource owner communicates with our authorization server.|
|Access Token 🔑||A token which is issued as a result of successful authorization. An access token can be obtained for a set of permissions (scopes) and has a pre-determined lifetime after which it expires.|
|Refresh Token 🔄||A special type of token that can be used to replenish the access token.|
Now, let us relate these terminologies in an abstract OAuth flow based on an example (1).
An end-user (resource owner 👤) grants a printing service (app 📦) access to their photo (resource 🖼) hosted in a photo-sharing service (resource server 📚), without sharing their username and password. Instead, they authenticate directly with a server trusted by the photo-sharing service (authorization server 🛡), which issues the printing service delegation-specific credentials (access token 🔑).
Note that our app (client) has to be registered in the authorization server in the first place. A Client ID is returned as a result. A client secret is also optionally generated depending on the scenario. This secret is known only to the authorization server and the application.
Okay, enough theory! It is time for some GIFs to understand the authorization scenarios/flows!
- Authorization Code Grant
- Authorization Code Grant with PKCE
- Client Credentials Grant
- Resource Owner Password Credentials Grant
- Implicit Grant
It is a popular browser-based authorization flow for Web and mobile apps. You can directly relate it with the above-mentioned example. In the diagram below, the flow starts from the Client redirecting the user to the authorization endpoint.
This flow is optimized for confidential clients. Confidential clients are apps that can guarantee the secrecy of
client_secret. A part of this flow happens in the front-channel (until the authorization code is obtained). As you can see, the
access_token 🔑 exchange step happens confidentially via back-channel (server-to-server communication).
Now you might naturally wonder, 'What about public clients?!'
Public clients using authorization code grant flow have security concerns. Be it single-page JS apps or native mobile apps, it is impossible to hide the
client_secret as the entire source is accessible (via DevTools or App Decompilation). Also, in native apps where there is a custom URI scheme, there is a possibility of malicious apps intercepting the authorization code via similar redirect URIs.
To tackle this, the Authorization Code Grant flow makes use of Proof Key for Code Exchange (PKCE). This enables the generation of a secret at runtime which can be safely verified by the Authorization Server. So how does this work?
Basically the client generates a random string named
Code Verifier (CV). A
Code transformation method (CM) is applied to the CV to derive a
Code Challenge (CC) ✨ As of now, there are two transformation methods
In plain transformation, CC will be equal to CV. This is not recommended for obvious security reasons & hence S256 is recommended. SHA256 is a hash function. On a high-level, it takes input data and outputs a string. However, there are special characteristics to this output string:
- This string is unique to the input data and any change in the input will result in a different output string! One can say, it is a signature of the input data.
- The input data cannot be recovered from the string and it is a one-way function (Refer the GIF above).
- The output string is of fixed-length.
You might have already guessed it. Take a look at the diagram to understand how CC is generated from CV. In this case, since SHA256 is used, CV cannot be generated from CC (Remember, it is a one-way transformation). Only CC can be generated from CV (Given that the transformation method is known -
S256 in our case).
Note that the flow starts with CV and CC generated first replacing the
Now that we know how CV, CC is generated, let us take a look at the complete flow. Most parts are similar to the authorization code grant flow. The CV and CC are generated even before the flow starts. Initially, only the CC and CM are passed to obtain an authorization code. Once the authorization code is obtained, the CV is sent along to obtain the access token.
In order for the authorization server to confirm the legitimacy, it applies the transformation method (CM, which is SHA256) on the received CV and compares it with the previously-obtained CC. If it matches, a token is provided! Note that even if someone intercepts the authorization code, they will not have the CV. Thanks to the nature of the one-way function, a CV cannot be recovered from CC. Also, CV cannot be found from the source or via decompilation as it is only generated during runtime!
In the above flows, a resource owner (user) had to provide consent. There can also be scenarios where a user's authorization is not required every time. Think of machine-to-machine communication (or app-to-app). In this case, the client is confidential by nature and the apps may need to act on behalf of themselves rather than that of the user.
Also, this is the simplest of all flows.
This flow is to be used only when there is a high degree of trust between the resource owner and the client. As you can see, initially, the username & password is obtained from the R.O and are used to fetch the
access_token. The username & password details will be discarded once the token is obtained.
This flow is not recommended for modern applications and is often only used for legacy or migration purposes. It carries high risk compared to other flows as it follows the password anti-pattern that OAuth wants to avoid in the first place!
This flow is no longer recommended officially! Implicit grant was considered an alternative to Authorization Code Grant for public clients. As you can notice, the public client does not contain the
client_secret and there is no back-channel involved. In fact, the access token is obtained immediately after the consent is obtained.
However, the token is passed in the URL fragment (Begins with
#) which will never be sent over the network to the redirect URL. Instead, the fragment part is accessed by a script that is loaded in the frontend (as a result of redirection). The
access_token will be extracted in this manner and subsequent calls are made to fetch the resources. As you can already see, this flow is susceptible to access token leakage and replay attacks.
It is recommended to use the Authorization Code Grant or any other suitable grant types instead of Implicit.
Feel free to share your thoughts as well. Don't forget to share this post if you found it useful 🚀
Let me know what you would like to see next as a part of the GIF series! Until then, stay OAuthsome!✨