You probably already have seen those "Sign in with Google" or "Connect with GitHub" buttons, which enable you to log in and access different services without entering a new set of credentials. Whether logging into a website using your social media account or authorizing a third-party app to interact with your email, OAuth 2.0 is the protocol behind this process.
This article will explain why OAuth 2.0 is essential, its core components, the authorization process, best practices, everyday use cases, and the various flows designed for different scenarios.
So, let’s dive in.
Catio: Your Copilot for Tech Architecture (Sponsored)
Unlock the potential of smarter decisions for your tech stack with Catio. Gain real-time observability, 24/7 AI-driven recommendations, and tailor-fit design patterns for your architecture to confidently build resilient and scalable tech stacks. Whether you’re designing with OAuth 2.0 or implementing other design patterns, Catio empowers your team to make data-backed decisions at every stage of the architecture lifecycle.
Ready to architect with AI expertise and elevate your tech stack?
We all remember when we needed to log in to every website or service we used, which implied that we needed to know the password for each one. As web services began to integrate, they started requesting users' credentials for other services to access critical data. This practice was dangerous in terms of security.
Then, OAuth was introduced to solve this problem. It tried to solve it by allowing Service A to securely access your information in Service B with your permission without needing your Service B credentials.
With OAuth, your food delivery service could access your social media, or your Facebook account could access your contacts. The key is that all this authorization remains under our control.
Why do we need OAuth 2.0 protocol?
In practice, OAuth 2.0 simplifies the user experience while maintaining security. When you see options like "Sign in with Google" or "Connect with Facebook," you see OAuth in action.
Here's a quick overview of how it works:
You connect an app (the client) to a service (the resource server).
The service asks for your permission, specifying what the app wants to access.
If you agree, the service gives the app a unique key (an access token).
The app uses this token to access your data on the service within the limits you approved.
This process allows applications to interact on your behalf without knowing your password.
What is OAuth 2.0?
OAuth 2.0 is an authorization framework that provides secure delegation of access to resources. Instead of sharing credentials, it uses tokens to grant limited access to a user's data from one site (the resource server) to another (the client) site.
The framework defines four roles:
💻 Client: The application requesting access to resources.
🔑 Resource Owner: The user who can grant or deny access to their data.
🛡️ Authorization Server: The server that issues access tokens to the client (ex: accounts.google.com).
🖥️ Resource Server: The server hosting the protected resources (it could be the same as the authorization server).
It includes the following resources:
📜 Authorization Grant: A token or code that proves the user has granted permission.
🔄 Redirect URI: The URL where the user is redirected after authentication, also known as the callback (e.g.,
yourwebsite.com/callback
).🔑 Access Token: The client's key to access data after receiving permission.
The process usually goes like this (Abstract protocol flow):
The user wants to access some resources in the app
The app requests authorization
User input credentials
App transfer credentials with OAuth keys to the Authorization Server
The authorization server returns the Access token
The app sends the access token to the resource server
The resource server serves the resource to the application
The app returns info to the user that the app is accessible
OAuth 2.0 Flows
OAuth 2.0 defines several grant types, each suited for different scenarios:
🌐 Authorization Code Flow: Used by web and mobile apps. It's the most common flow, and it acquires an authorization code to exchange for an access token, ensuring the client never exposes the tokens to the user-agent.
🖥️ Client Credentials: For server-to-server authentication, a client can use its credentials instead of impersonating a user to obtain an access token.
📱 Device Code: Used for devices with limited input capabilities.
⚠️ Implicit Flow: Previously used for client-side applications like SPAs, it directly returns an access token upon authorization but lacks refresh tokens and is less recommended due to security issues. It is deprecated due to security weaknesses and will disappear in OAuth 2.1.
👤 Resource Owner Password Credentials: This flow allows the client to use the resource owner’s username and password directly. It is suitable for highly trusted or legacy applications but is discouraged due to security risks.
➡️ How can we decide which flow to use?
If the requesting party is a machine, not a person, in a machine-to-machine authorization, we can use the Client Credentials Flow.
We should use the Authorization Code Flow if the client executes a web application on the server.
A particular case is native mobile apps, where we should use Authorization Code Flow with Proof Key for Code Exchange (PKCE).
Also, we have the following tokens in use with OAuth 2.0:
🔑 Access Token: Short-lived token used to access protected resources.
♻️ Refresh Token: Long-lived token used to obtain new access tokens.
🆔 ID Token: Contains claims about the authentication of an end-user (specific to OpenID Connect).
OAuth 2.0 Implementation
When implementing OAuth 2.0, we should take the following steps:
Register your application: Obtain client credentials from the authorization server.
Choose the appropriate flow Based on your application type and requirements.
Implement the chosen flow: Follow the OAuth 2.0 specification for the selected grant type.
Handle and store tokens securely: Implement proper token management.
Validate tokens: Always validate received tokens before trusting them.
Implement token refresh: Use refresh tokens to maintain long-term access.
Authorization Code Flow 🔒
The authorization code grant type is the most common one because it is best suited for server-side applications where source code is not publicly available and Client Secret confidentiality can be preserved. This is a redirection-based flow, which means that the application must be able to connect with the user agent (the user's web browser) and receive API permission codes sent through it.
We should use the Authorization Code Flow for web and mobile apps. It exchanges authorization codes, adding a layer of security.
The implementation of the Authorization Code Flow goes like this:
The client initiates the flow by redirecting the user to the authorization server.
Here’s each query parameter explained:
response_type=code
- This tells the authorization server that the application initiates the authorization code flow. Always set to "code" for the Authorization Code Flow.client_id
- The unique identifier for your application was obtained when the developer first registered it. It tells the authorization server which application is making the request.redirect_uri
- The URL where the user should be sent after authorization.scope
- A space-separated list of permissions your app is requesting. It defines what access privileges your application is asking for. For example,scope=read_user write_posts
.state
- A random string your application generates and includes in the request. It should then check that the exact value is returned after the user authorizes the app. This is used to prevent CSRF attacks.
The user authorizes the client (an example).
The authorization server redirects back to the client with an authorization code if the client approves the code. The
state
value is the same as the application initially set in the request and the authorization code generated by the authorization server.Now, the client exchanges the authorization code for an access token with a POST request.
The authorization server responds with an access token (and, optionally, a refresh token).
Now, the client does what originally wanted: access the resource server, which will be allowed due to the attached access token to the request.
What happens here is that a client wants to access something he is not allowed to. The resource server will not allow it, so we have the scope in OAuth.
⚠️ Note that we should always use PKCE (Proof Key for Code Exchange) for added security, especially in mobile apps. In general Authorization Flow, the attacker can intercept the authorization code sent to the client and exchange it for an access token, which means it can access resources on our behalf. This is usually done by registering malicious apps on the user’s device. So, PKCE tries to resolve this security issue by introducing a new flow and parameters: Code Verifier (a random string), Code Challenge, and the Code Challenge Method. These additional parameters work together to securely bind the authorization request to the client that initiated it. By requiring the code verifier during the token exchange, PKCE ensures that even if an attacker intercepts the authorization code, they cannot exchange it for an access token without the correct code verifier. Learn more about it here.
Refresh Token Flow 🔄
When an access token expires, attempting to make a call from the API will return an Invalid Token Error. If a refresh token was issued along with the initial access token, it can now be used to request a new access token from the authorization server.
Here's how the Refresh Token Flow works:
The client detects that the access token has expired.
The client sends a request to the token endpoint with the refresh token
Here's an example POST request using a refresh token to get a new access token:
The authorization server validates the refresh token and issues a new access token:
OAuth 2.0 Use Cases
Some everyday use cases for OAuth 2.0 usage are the following:
Use case 1: Third-Party Access 🔗
Users can grant third-party applications limited access to their resources without sharing their credentials, like allowing a photo printing service to access photos stored in a cloud service.
For example, A user allows a scheduling app to access their Google Calendar to automatically set up meetings without sharing their Google credentials.
Use case 2: Single Sign-On (SSO) 🔑
It facilitates Single Sign-On (SSO), where users can log in to multiple services using a single ID, streamlining the authentication process across platforms and services.
Read more about SSO here:
For example, An employee logs into their corporate network and can access different departmental applications like email, HR system, and project management tool without logging in again.
Use case 3: Mobile applications 📱
OAuth 2.0 provides a framework for mobile apps to obtain the necessary tokens to access protected resources, ensuring secure operations.
For example, A user downloads a fitness app which, upon authorization via OAuth 2.0, accesses their Spotify playlists to play music during workouts without requiring separate logins.
And the list of the most common OAuth providers.
OAuth 2.0 Best Practices
When implementing OAuth 2.0 into our applications workflows, we should take into account the following best practices:
Use proven libraries: Don't implement OAuth 2.0 from scratch; use well-maintained libraries.
Use short-lived access tokens: Limiting access tokens' lifespan helps mitigate the harm if they are hacked. You can use Refresh tokens to receive new access tokens without contacting the user.
Use HTTPS: Always use TLS for all OAuth 2.0 interactions.
Keep secrets secret: Never expose client secrets or tokens in client-side code.
Use PKCE: Implement Proof Key for Code Exchange to prevent CSRF and authorization code injection attacks.
Limit token scope: Request only the permissions your application needs (minimal scope).
Handle errors gracefully: Implement proper handling as defined in the OAuth 2.0 spec.
OAuth 2.0 Drawbacks
Here are a few problems you can have dealing with the OAuth 2.0
Issue 1: OAuth is complex 🔄
Using this protocol has some cons, too. First, implementing OAuth 2.0 can be complex, especially for developers unfamiliar with its concepts and flows, as it is a big standard.
On the official website, you can find over 17 RFCs with 72 parameters defining how OAuth 2.0 works. This usually leads to teams implementing the bare minimum of OAuth 2.0 for the particular scenario.
Issue 2: Misuse of the protocol 🚫
Next, while OAuth 2.0 is designed for authorization, it’s sometimes mistaken for an authentication protocol, which it’s not. This misconception can lead to wrong implementations and security risks.
OAuth 2.0 is designed to grant applications limited access to a user's resources on another system without sharing the user's credentials. It answers the question, "What is this application allowed to do on behalf of the user?" rather than "Who is this user?" so it doesn’t know who just logged in with their e-mail.
OpenID Connect was developed to address authentication needs alongside OAuth 2.0's authorization capabilities. It is an identity layer built on top of OAuth 2.0. It uses ID tokens (in the form of JWT — JSON Web Token) with some usage information and provides standardized ways to authenticate users and obtain basic profile information. Suppose we connect to an authorization server that supports OpenID Connect. In that case, we may request an access token, an ID token, and all the information at the /UserInfo endpoint.
Issue 3: Inconsistent implementation ⚠️
Also, the specification leaves room for interpretation, leading to inconsistent implementations across different service providers, which can cause interoperability issues.
In the first case, everyone uses it differently in the wild. For example, some APIs use different parameters depending on what is required in the authorization call and what they want to see in the token request call.
In the second case, we see different nonstandard extensions added to OAuth. This can be, for example, that you need to add some data in addition to the access_token
to be able to work with API.
More ways I can help you
LinkedIn Content Creator Masterclass ✨. In this masterclass, I share my strategies for growing your influence on LinkedIn in the Tech space. You'll learn how to define your target audience, master the LinkedIn algorithm, create impactful content using my writing system, and create a content strategy that drives impressive results.
Resume Reality Check" 🚀. I can now offer you a new service where I’ll review your CV and LinkedIn profile, providing instant, honest feedback from a CTO’s perspective. You’ll discover what stands out, what needs improvement, and how recruiters and engineering managers view your resume at first glance.
Promote yourself to 35,000+ subscribers by sponsoring this newsletter. This newsletter puts you in front of an audience with many engineering leaders and senior engineers who influence tech decisions and purchases.
Join my Patreon community: This is your way of supporting me, saying “thanks, " and getting more benefits. You will get exclusive benefits, including all of my books and templates on Design Patterns, Setting priorities, and more, worth $100, early access to my content, insider news, helpful resources and tools, priority support, and the possibility to influence my work.
1:1 Coaching: Book a working session with me. 1:1 coaching is available for personal and organizational/team growth topics. I help you become a high-performing leader and engineer 🚀.