Most people have used OAuth 2.0 without realizing it.
Any time you click “Continue with Google,” connect a calendar app to another tool, authorize a developer platform to access GitHub, or allow Slack to connect with another service, OAuth is probably involved.
OAuth 2.0 is an authorization framework that lets one application access protected resources from another service without asking for the user’s password. The official OAuth 2.0 specification describes it as a way for third-party applications to obtain limited access to an HTTP service, either on behalf of a user or on the application’s own behalf.
In simpler terms: OAuth lets users say, “Yes, this app can access this specific thing,” without handing over passwords or full account access.
The core idea is simple: instead of sharing credentials, the user grants limited permission. The application receives an access token, and that token allows the app to call an API within a defined set of permissions.
Table of Contents
OAuth 2.0 is a framework for delegated authorization. It allows one application to access specific protected resources from another service without requiring the user to share their password.
For example, a scheduling app can ask for permission to read your calendar events. If you approve, the app receives an access token that allows it to call the calendar API within the limits of the permissions you granted.
OAuth is not about giving an app full control of your account. It is about granting limited access to specific resources for a specific purpose.
Before OAuth 2, integrations were often handled in unsafe ways. A user might give an app their username and password so the app could log in on their behalf, perform actions, or access protected data.
That created obvious problems:
OAuth changes the model. Instead of sharing a password, the user grants permission. The app receives an access token, which represents the authorization to access specific protected resources.
One of the most common misconceptions is that OAuth 2.0 is a login protocol.
OAuth 2.0 is primarily about authorization. It answers this question:
Is this application allowed to access this protected resource?
It does not, by itself, answer:
Who is this user?
That second question is authentication. When an app offers “Sign in with Google,” it is usually using OpenID Connect, or OIDC.
OpenID Connect is an identity layer built on top of OAuth 2.0. It lets a client verify the identity of the end user and receive basic profile information.
Whenever OpenID Connect is involved, OAuth 2.0 is involved. But OAuth 2.0 does not necessarily mean OpenID Connect is involved.
A useful shorthand:
The OAuth 2.0 specification defines four main roles.
The resource owner is the entity that can grant access to a protected resource. In many common OAuth flows, this is the user.
For example, if you authorize a scheduling app to read your Google Calendar, you are the resource owner.
The client is the application requesting access.
For example, a scheduling app that wants to read your calendar events is the client.
The authorization server authenticates the resource owner, obtains authorization, and issues access tokens to the client.
For example, when you connect Google Calendar to another app, Google’s authorization server is responsible for asking you to sign in and approve the requested access.
The resource server hosts the protected resource and accepts access tokens.
For example, the server behind the Google Calendar API is the resource server.
At a high level, OAuth 2.0 defines a flow for granting access to protected resources.
The exact steps vary depending on the OAuth grant type, but the general pattern looks like this:
That is the formal version. Here is what OAuth 2.0 looks like in practice:
The important part is that the app never receives the user’s Google password. The authorization server handles user authentication and consent. The app receives a token that represents scoped permission to access specific protected resources.
For example, the token might allow the app to read calendar events but not delete them. That limitation is the power of OAuth: it allows specific access to specific resources without giving away full account control.
Imagine a friend asks to borrow your phone to look up directions.
One option is to give them your phone’s passcode and let them unlock the device themselves. That gives them far more access than they need. They could open your messages, email, photos, banking apps, or anything else on the device.
Another option is to unlock the phone yourself and hand it to them with the maps app already open.
The first option is similar to the risky pattern that existed before OAuth: sharing credentials with a third-party application.
The second option is closer to the idea behind OAuth: granting limited access for a specific purpose.
The analogy is not perfect because your friend could still start opening other apps if they are nosy. But this is where OAuth scopes matter. In OAuth 2.0, scopes limit what the client is allowed to access or do.
Scopes define what an application is allowed to do.
An app might request scopes such as:
read:calendar write:calendar read:contacts
A scheduling app may need permission to read calendar events. It may not need permission to delete calendars or access contacts.
Good OAuth implementations make scopes visible to the user so the user understands what they are granting.
A well-designed app should request the smallest set of scopes it needs. This is often called the principle of least privilege in security.
An access token is a credential that lets an application access a protected API via the resource server.
You can think of an access token like a temporary key card, like something you’d get for your hotel room. Just like you don’t get access to all the rooms in the hotel and are limited to your room, an access token allows access to a specific thing for a specific amount of time or has an expiration date. It does not reveal the user’s password, and it can be limited by scope, audience, and expiration time.
However, access tokens should be treated as secrets. If someone steals a valid access token, they may be able to use it until it expires or is revoked.
That is why developers need to store tokens securely, avoid leaking them in logs, and avoid exposing them. That is why developers need to store tokens securely, avoid leaking them in logs, and avoid exposing them in places where attackers can easily capture them. Developers should also follow other security best practices like limiting scope, audience, and expiration to reduce the potential damage if a token is leaked.
Access tokens are best short-lived. That is good for security because it shrinks the window of opportunity for malicious actors to steal and use them, but it creates a usability problem: users do not want to re-authorize an app every few minutes.
Refresh tokens solve this problem. A refresh token is something that can be sent along with an access token and can be used to obtain a new access token when the old one expires without requiring the user to repeat the entire authorization process.
Refresh tokens are powerful and need strong protection. If a refresh token is compromised, an attacker may be able to keep obtaining new access tokens until the refresh token is revoked or expires, often much longer than an access token’s lifetime.
The authorization code flow is the most common modern OAuth 2.0 flow for applications that need to access resources on behalf of a user and follows current best practice.
In this flow:
This is safer than returning the access token directly in the browser redirect, which is known as the implicit flow, because the token exchange happens separately from the front-channel redirect.
Modern OAuth guidance also recommends using PKCE, or Proof Key for Code Exchange, with the authorization code flow. PKCE adds an extra layer of protection by making it harder for an attacker to use a stolen authorization code.
PKCE stands for Proof Key for Code Exchange. It is pronounced “pixy,” and it is an extension to OAuth 2.0 that makes the authorization code flow more secure.
PKCE was originally created to protect public clients, such as mobile apps and browser-based applications. These apps cannot safely store a client secret because their code runs on a user’s device or in the browser, where secrets can be inspected or extracted.
The main problem PKCE helps solve is called an authorization code interception attack. In the authorization code flow, the authorization server sends an authorization code back to the client after the user approves access. If an attacker manages to intercept that code, they may try to exchange it for an access token and gain access to the protected resource.
PKCE makes that stolen authorization code much less useful by requiring the client to prove that it is the same application that started the authorization request.
PKCE adds two important values to the authorization code flow:
The flow looks like this:
code_verifier.code_challenge from that verifier.code_challenge with the initial authorization request.code_verifier to the token endpoint.This means that even if an attacker steals the authorization code, they still need the original code verifier to exchange that code for an access token. Since the verifier was never sent in the initial authorization request, the attacker should not have it.
Imagine a hotel where a guest wants to access a room, but a front desk assistant helps complete the check-in process. The guest approves the room access, but the front desk assistant is the one responsible for exchanging the temporary claim ticket for the final room keycard.
Here is how the hotel analogy maps to OAuth 2.0:
code_verifier, generated by the client.code_challenge, sent by the client at the start of the flow.At the beginning of the process, the front desk assistant creates a private phrase and gives the hotel check-in system a safe fingerprint of that phrase. The hotel check-in system stores the fingerprint, but not the original phrase.
The guest then approves access. After that approval, the hotel check-in system gives the front desk assistant a claim ticket. That claim ticket is not the room keycard yet. It still has to be exchanged for the final keycard.
Without PKCE, someone who steals the claim ticket can bring it to the hotel check-in system and exchange it for the room keycard.
With PKCE, the claim ticket alone is not enough. When the front desk assistant exchanges the claim ticket, they must also reveal the original private phrase. The hotel check-in system compares that phrase to the safe fingerprint it received earlier. If they match, the hotel issues the room keycard. If they don't, the request is rejected.
Mapped back to OAuth: the client generates the code_verifier (a generated secret), sends the code_challenge (the transformed secret) with the initial authorization request, receives the authorization code after the user approves access, and later proves possession of the original code_verifier when exchanging the authorization code for an access token.
This is why a stolen authorization code is not enough. The attacker would also need the client’s original code verifier which is kept private to the client.
PKCE is now considered a security best practice for the authorization code flow. It is especially important for public clients, but modern OAuth guidance increasingly recommends it for all clients using the authorization code flow.
PKCE does not replace other OAuth security practices. Developers still need strict redirect URI validation, secure token storage, least-privilege scopes, and short-lived access tokens. PKCE specifically helps protect the authorization code exchange from interception and misuse.
OAuth 2.1 is an in-progress effort to consolidate OAuth 2.0 and the considerable later security guidance into a simpler core specification.
It reflects modern best practices such as using PKCE for clients using the authorization code flow, omitting the implicit grant, omitting the resource owner password credentials grant, and tightening redirect URI handling.
Because OAuth 2.1 is still an Internet-Draft, it is better to describe it as work in progress rather than as a finalized standard.
OAuth 2.0 is now a core building block for API access and app integrations.
It enables:
For developers, understanding OAuth helps prevent dangerous mistakes like storing user passwords, requesting excessive scopes, leaking tokens, or confusing authorization with authentication.
OAuth is powerful, but it needs to be implemented carefully.
Modern OAuth security guidance recommends practices such as:
The IETF’s OAuth 2.0 Security Best Current Practice, published as RFC 9700, updates earlier OAuth security guidance and deprecates some modes of operation considered less secure or insecure.
Common OAuth mistakes include:
These mistakes are common because OAuth is both flexible and widely used. The flexibility is useful, but it also means developers need to understand which flow, token type, and security practices apply to their use case. Solutions for these are covered by the security best practices.
OAuth 2.0 is a framework that lets one application access specific resources from another service without needing the user’s password.
For example, a scheduling app can use OAuth 2.0 to request permission to read your calendar events. If you approve, the app receives an access token that lets it call the calendar API within the permissions you granted.
No. OAuth 2.0 is about authorization, not authentication.
OAuth answers: “Is this application allowed to access this resource?”
Authentication answers: “Who is this user?”
If you want login, you usually need OpenID Connect, which is an identity layer built on top of OAuth 2.0.
OAuth 2.0 lets applications request access to protected resources.
OpenID Connect lets applications verify the identity of a user.
OpenID Connect uses OAuth 2.0 underneath, but adds identity-specific features such as ID tokens and standardized user profile information.
An access token is a credential that lets an application call an API. It represents the permission granted to the application.
Access tokens can be limited by scope, expiration time, and audience.
A refresh token is a credential used to obtain new access tokens without asking the user to authorize the app again.
Refresh tokens are powerful and should be stored securely.
Scopes are permissions that define what an application is allowed to do.
For example, an app might request permission to read calendar events but not modify or delete them.
PKCE, or Proof Key for Code Exchange, is a security extension for the OAuth 2.0 authorization code flow.
It works by having the client create a temporary secret called a code verifier and send a related code challenge during the authorization request. Later, when the client exchanges the authorization code for an access token, it must provide the original verifier.
This helps prevent attackers from using a stolen authorization code because the code alone is not enough to get an access token.
OAuth 2.0 can be secure when implemented correctly. However, poor implementation choices can create serious risks.
Developers should use modern best practices such as the authorization code flow with PKCE, strict redirect URI validation, least-privilege scopes, secure token storage, and short-lived access tokens.
OAuth 2.1 is a draft specification that consolidates OAuth 2.0 and later security guidance into a more modern core framework.
It is not yet a finalized RFC, so it should be described as work in progress.
OAuth 2.0 is the standard way modern applications delegate access.
It lets users authorize applications to access specific protected resources without sharing passwords. It gives developers a structured way to request limited permissions. And it gives platforms a safer model for building integrations.
The key idea is simple:
OAuth is not about giving an app your password. It is about giving an app permission.
Used correctly, OAuth makes connected software safer, more flexible, and easier to trust.