Introduction
You click "Sign in with Google" on a new app, approve the request, and you are logged in. You never typed your Google password into the new app, and the app never saw it. A photo-printing service can read your photos, but it cannot read your emails. A calendar app can add events, but it cannot delete your account. That is OAuth at work: a standard that lets one application act on your behalf in another service, without ever handling your password.
OAuth is everywhere, and most people use it every day without knowing its name. It is also widely misunderstood, and misunderstood security is dangerous. Teams that implement it carelessly create the very risks it was designed to prevent. This guide explains OAuth in plain language: what problem it solves, how it works, what the tokens and scopes actually mean, how it differs from logging in, and the mistakes that cause real breaches.
The Problem OAuth Solves
Before OAuth, the usual way for one application to access your data in another service was to ask for your password. A small app that wanted to print your photos would ask for your email password, store it, and log in as you. That gave the app far more access than it needed — it could read your emails, change your settings, and lock you out — and it meant your password was stored in yet another place, where it could be stolen.
There was also no way to take that access back without changing your password, which would break every other app you had given it to. And if the small app was compromised, the attacker got your password, not just access to your photos.
OAuth solves this by separating permission from identity. Instead of giving an app your password, you give it a token: a limited, revocable credential that says what the app is allowed to do, and for how long. The app uses the token to call the service on your behalf, and the service checks the token before it does anything. If you change your mind, you revoke the token, and the app loses access without your password ever changing.
The Four Roles in OAuth
OAuth has four roles, and it helps to keep them straight, because the documentation uses their names everywhere.
The resource owner is you, the person whose data is being accessed. You are the one who approves or denies the request.
The client is the application asking for access, such as the photo-printing app. It is called a client because it is a client of the service holding your data, not because it runs on your computer.
The authorization server is the service that checks who you are and issues tokens. When you click "Sign in with Google", Google's authorization server is the one that asks you to approve the request.
The resource server is the service that holds your data and checks the token before it hands anything over. Often the authorization server and the resource server are run by the same company, such as Google, but they are different jobs and it helps to think of them separately.
A fifth term you will see is scope. A scope is a permission, such as "read your photos" or "add calendar events". When you approve a request, you approve a set of scopes, and the token the app receives is only valid for those scopes. An app that asks for "read your photos" cannot use the same token to read your emails, because that scope was never granted.
How the Authorization Code Flow Works
The most common OAuth flow is the authorization code flow, and it is the one you should use for web applications. It has several steps, but the idea is simple: the app never sees your password, and the token is delivered securely to the app's server, not through your browser.
First, the app redirects you to the authorization server, with a request that says who it is, what scopes it wants, and where to send you back afterwards. That return address is called the redirect URI, and it must match exactly a value the app registered in advance. If it does not match, the request is refused.
Second, you log in to the authorization server — if you are not already logged in — and you see a screen that says what the app is asking for. You approve or deny the request. This is the moment that matters for you as a user: read what the app is asking for, and do not approve scopes it does not need.
Third, the authorization server redirects you back to the app, with a short-lived code in the address. That code is not a token. It is a single-use voucher that the app can exchange for a token.
Fourth, the app's server sends that code, together with its own secret credential, directly to the authorization server, over a secure connection that your browser never sees. The authorization server checks the code and the secret, and if both are correct, it returns two tokens: an access token and usually a refresh token.
The access token is what the app uses to call the resource server. It is short-lived, often an hour or less, and it is sent with each request. The resource server checks it, and if it is valid and has the right scope, it returns the data.
The refresh token is longer-lived, and the app uses it to get a new access token when the old one expires, without asking you to log in again. Because a refresh token is powerful, it should be stored securely on the app's server and never sent to a browser or a mobile app's code where it could be extracted.
For mobile and single-page applications, there is an important addition called PKCE, short for Proof Key for Code Exchange. The app creates a random secret before it starts the flow, sends a hash of it with the first request, and proves it knows the secret when it exchanges the code. PKCE prevents an attacker who intercepts the code from using it, and it is now recommended for all clients, not just mobile apps.
OAuth Is Not Authentication
This is the most important misunderstanding about OAuth, and it causes real security problems. OAuth is about authorization: permission to do something on your behalf. It is not, by itself, about authentication: proving who you are.
An access token says "the holder of this token is allowed to read this user's photos". It does not, on its own, prove that the person holding it is that user, or tell the app who the user is in a reliable way. Teams that treat an access token as proof of identity can be tricked: an attacker who obtains a token meant for one app can sometimes use it to log in to another app as the victim.
The standard that adds authentication on top of OAuth is called OpenID Connect. It adds an ID token, which is a signed statement from the authorization server saying who the user is, when they logged in, and which app the token was issued for. If you need to know who the user is — which most login flows do — use OpenID Connect, not plain OAuth. "Sign in with Google" is OpenID Connect, built on OAuth, and that distinction is why it works as a login.
A practical rule follows from this: use OAuth to get permission to call an API, and use OpenID Connect to log a user in. Do not invent your own way of turning an access token into a login.
The Other Flows, and When to Use Them
The authorization code flow with PKCE is the recommended flow for almost everything. The other flows exist for specific cases, and some of them should be avoided.
The client credentials flow is for machine-to-machine access, where no user is involved. A background service that needs to call an API uses its own credential to get a token for itself, not on behalf of a user. This is the right flow for a server talking to another server.
The device authorization flow is for devices with no browser, such as a smart TV. The device shows you a code, you visit a website on your phone and enter the code, and the device gets a token. It is a good fit for that problem, and a poor fit for anything with a browser.
The implicit flow used to be recommended for single-page applications, because it returned the token directly in the browser. It is now deprecated, because a token in a browser address bar can be leaked through browser history, logs, and referrer headers. Use the authorization code flow with PKCE instead.
The resource owner password credentials flow, where an app asks you for your password and sends it to the authorization server, defeats the whole purpose of OAuth. It should only be used when the app and the authorization server are run by the same organisation and there is no alternative, and even then it is a sign that something should be redesigned.
If a tutorial tells you to use the implicit flow or the password flow for a new application, that tutorial is out of date.
Scopes, Tokens, and Least Privilege
Good OAuth design follows the principle of least privilege: ask for the smallest set of scopes that lets the app do its job, and no more. An app that only needs to read your calendar should not ask for permission to delete it. An app that only needs your name and email should not ask for access to your files.
As a user, you can apply the same principle when you see an approval screen. If a simple app asks for broad access to your account, that is a reason to pause and ask why. You can usually revoke access later from the service's security settings, under a page called "third-party access" or "connected apps", and it is worth reviewing that list from time to time and removing apps you no longer use.
As a developer, there are a few rules that matter. Request scopes incrementally, when the feature that needs them is used, rather than asking for everything at sign-up. That makes the request easier to understand and easier to approve. Store refresh tokens encrypted, and store them on the server, not in a browser or in mobile app code. Set a short lifetime for access tokens, so a stolen token is useful only briefly. And log token use, so you can see if a token is being used in an unusual way.
Tokens themselves come in two kinds. An opaque token is a random string that means nothing on its own; the resource server must ask the authorization server whether it is valid. A JWT access token is a signed statement that contains the scopes and the expiry, so the resource server can check it without another call. JWTs are convenient, but they cannot be revoked instantly in the same way, because they remain valid until they expire unless the resource server checks a revocation list. That is one more reason to keep their lifetime short.
Common Security Mistakes
OAuth is a standard, but a standard implemented badly is worse than no standard, because it looks secure while it is not. The mistakes that cause breaches are usually the same few, repeated.
Not checking the redirect URI is the first. If an app accepts any redirect address, an attacker can send a victim to a login page, have the code sent to the attacker's own site, and use it to get a token. The authorization server must check the redirect URI against a registered value, exactly, not approximately.
Skipping the state parameter is the second. The state value is a random string the app creates before the flow and checks when the user returns. Without it, an attacker can start a login flow with their own account and trick a victim's browser into completing it, logging the victim in as the attacker. That is called a cross-site request forgery attack, and the state parameter prevents it.
Storing tokens in the wrong place is the third. Access tokens and especially refresh tokens should not be stored in browser local storage, in a mobile app's code, or in a log file. A token in local storage can be read by any script running on the page, which is why a cross-site scripting vulnerability becomes a full account compromise when tokens are stored there.
Using the wrong flow is the fourth, as described above: the implicit flow, or the password flow, where the authorization code flow with PKCE would do.
Trusting a token without checking it is the fifth. A resource server must validate the token's signature, its expiry, its audience — which app it was issued for — and its scope, on every request. Accepting a token issued for a different app, or one that has expired, is a common implementation bug.
Asking for too much is the sixth, and it is a design mistake as well as a security one. Broad scopes mean a stolen token does more damage, and they make users less likely to trust the app.
Where OAuth Is Used Today
OAuth is used wherever one service needs to act on your behalf in another. "Sign in with" buttons are the most visible example, and they are OpenID Connect on top of OAuth. Social apps that post on your behalf, photo apps that read your library, and calendar apps that add events all use it.
In business software, OAuth lets a CRM read a mailbox, a reporting tool read a spreadsheet, and a support tool read tickets, each with only the scopes it needs. That is what makes integrations safe to offer: a customer can connect two tools without handing over a password.
In APIs, OAuth is the standard way to protect access. An API that serves many different apps issues each one a token with the scopes that app was granted, and it can revoke a single app without affecting the others. That is far easier to manage than sharing a single API key.
In mobile apps, OAuth with PKCE is the standard way to log a user in and keep them logged in with refresh tokens, without storing a password on the device.
Implementing OAuth Safely
If you are adding OAuth to an application, do not implement the protocol from scratch. Use a well-maintained library for your language and framework, and use a well-known authorization server or identity provider rather than building your own. The protocol has many details that are easy to get wrong, and a library that has been reviewed by many people is safer than code written from a tutorial.
Use the authorization code flow with PKCE, and OpenID Connect if you need to know who the user is. Register your redirect URIs exactly, and do not accept wildcards. Generate and check the state parameter. Store refresh tokens securely on the server. Keep access tokens short-lived. Validate tokens properly on the resource server, including signature, expiry, audience, and scope.
Test the failure cases, not just the happy path. What happens if a user denies the request? What happens if a token expires in the middle of a task? What happens if a token is revoked? A good implementation handles those gracefully, with a clear message and a way to reconnect, rather than crashing or silently failing.
Finally, give users a way to disconnect. A settings page that shows which apps have access and lets a user revoke them is part of the feature, not an afterthought, and it is what makes the whole model trustworthy.
Conclusion
OAuth is, at its core, a way to give an application limited, revocable permission to act on your behalf, without ever giving it your password. The authorization code flow, with PKCE, is the standard way to do that safely. Scopes limit what a token can do, access tokens are short-lived, and refresh tokens let an app stay connected without asking you to log in again.
It is not authentication on its own — that is OpenID Connect — and it is not secure just because it is a standard. Its security depends on the details: checking the redirect URI, using the state parameter, storing tokens properly, validating them on every request, and asking for the least privilege the app needs. Get those details right, and OAuth is one of the most practical security tools on the modern web. Get them wrong, and it can look secure while leaving the door open.
Frequently Asked Questions
Is "Sign in with Google" OAuth? It is OpenID Connect, which is built on OAuth. OAuth provides the permission and the tokens, and OpenID Connect adds the ID token that tells the app who you are. That combination is what makes it a login, not just an authorization.
Can an app see my password if I use OAuth? No. You type your password only into the authorization server's own login page, such as Google's, and the app never sees it. That is the point of the flow. If an app asks you to type your Google password into its own page, do not do it.
How do I revoke an app's access? Go to the security settings of the service whose data it accesses — for Google, that is the "Third-party access" page — find the app, and remove its access. The app's tokens stop working, and it cannot get new ones without you approving again.
What is the difference between an access token and a refresh token? An access token is short-lived and is used to call the API. A refresh token is longer-lived and is used to get a new access token when the old one expires. A refresh token is more powerful, so it must be stored more carefully.
Why do I have to log in again sometimes if I have a refresh token? Refresh tokens can expire, be revoked, or be invalidated when you change your password or the app's permissions change. When that happens, the app must ask you to approve the request again. That is normal, and it is a safety feature, not a bug.
Comments
Post a Comment