System Design
OAuth 2.0 Explained
Every time you click 'Log in with Google,' OAuth 2.0 is working behind the scenes - letting an app access part of your account without ever seeing your password. Here's how that actually works, demystified.
You've done it a hundred times: an app asks "Log in with Google?" or "Connect your account," you click, a familiar consent screen appears, you approve, and suddenly the app has access to part of your account - your profile, your contacts, your files - without you ever giving that app your password. The framework making this possible is OAuth 2.0, and it's one of the most important and most misunderstood pieces of modern web security. This guide explains what OAuth 2.0 actually does, the flow behind "Log in with X," and the crucial distinction it's built on.
The problem OAuth solves
Start with the problem. Suppose a photo-printing app wants to access your Google Photos to print them. The naive solution would be to give the app your Google password. This is terrible: now the app has full access to your entire Google account (not just photos), forever, and you have to trust it with your actual password - which it could store, leak, or misuse. Sharing your password gives away far too much, irrevocably.
OAuth 2.0 solves this: it lets you grant an app limited access to specific parts of your account, without sharing your password, and revocably. The photo app gets permission to access only your photos, you never reveal your password to it, and you can revoke that access anytime. OAuth is the framework for delegated authorization - letting you delegate limited access to a third party, safely, without that third party ever becoming a holder of your actual credentials.
The four roles
OAuth involves four parties, and naming them makes the flow clear:
- Resource owner - you, the user who owns the data and grants access.
- Client - the application requesting access (the photo-printing app).
- Authorization server - the system that authenticates you and issues access tokens (Google's OAuth server).
- Resource server - the system holding the protected data (Google Photos' API).
The whole dance is about the client getting permission, from you, via the authorization server, to access your data on the resource server - without the client ever seeing your credentials.
How it works: the authorization flow
Here's the core OAuth flow (the "authorization code" flow, the standard for web apps), step by step:
- Initiate. You click "Connect with Google" in the app (the client). The app redirects you to Google's authorization server.
- Authenticate and consent. At Google (not the app), you log in (if not already) and see a consent screen telling you exactly what the app is asking to access ("This app wants to view your photos"). You approve or deny. Crucially, you're entering your password at Google, never at the app.
- Authorization code. If you approve, Google redirects you back to the app with a temporary authorization code - a short-lived, one-time code representing your grant.
- Exchange for a token. The app sends this code (along with its own credentials proving it's the legitimate app) back to Google's authorization server, which exchanges it for an access token.
- Access the resource. The app uses the access token to make requests to the resource server (Google Photos' API). The token grants access to only what you consented to.
So the app ends up with an access token scoped to your photos - and never touched your password. You authenticated directly with Google; the app only ever received a code and then a token.
sequenceDiagram
participant U as You (resource owner)
participant C as App (client)
participant A as Authorization server
participant R as Resource server
U->>C: Click "Connect with Google"
C->>A: Redirect you to authorize
U->>A: Log in + consent (at Google, not the app)
A-->>C: Authorization code
C->>A: Exchange code (+ app credentials) for token
A-->>C: Access token
C->>R: Request data with access token
R-->>C: Your photos (only what you consented to)
This sequence diagram shows the OAuth authorization code flow. You click connect with Google in the app. The app redirects you to the authorization server, where you log in and consent - at Google, never giving your password to the app. Google sends the app a temporary authorization code. The app exchanges that code, along with its own credentials, for an access token. The app then uses the access token to request your data from the resource server, which returns only what you consented to share. Your password never reached the app.
Access tokens, scopes, and refresh tokens
A few concepts make OAuth's access control precise:
- Access token. The credential the app uses to access your data. It represents the permission you granted, and the app includes it with each request to the resource server. Access tokens are typically short-lived for security (often JWTs, in fact - the token-carrying-claims idea from the JWT guide).
- Scopes. The specific permissions being granted. OAuth lets the app request particular scopes ("read your photos," "read your email") and you consent to exactly those - so access is limited to what's needed, not your whole account. Scopes are how OAuth delivers limited access.
- Refresh token. Because access tokens are short-lived, OAuth often also issues a longer-lived refresh token that the app can use to get a new access token when the old one expires - so you don't have to re-consent constantly, while access tokens stay short-lived for safety. The refresh token can be revoked to cut off the app's access entirely.
Together, scopes (limited permissions), short-lived access tokens (limited exposure), and refresh tokens (sustained-but-revocable access) give OAuth fine-grained, controllable delegation.
The crucial distinction: authorization vs. authentication
Here's the point that confuses almost everyone, and that signals real understanding when you get it right: OAuth 2.0 is an authorization framework, not an authentication one.
- Authentication is about who you are - verifying your identity (logging in).
- Authorization is about what you're allowed to do - granting permission to access resources.
OAuth 2.0 is fundamentally about authorization - granting an app limited access to your resources. It was not originally designed to tell the app who you are. But "Log in with Google" is clearly about identity (authentication) - so what's going on?
The answer: "Log in with X" uses OpenID Connect (OIDC), a thin layer built on top of OAuth 2.0 that adds authentication. OIDC uses OAuth's flow but adds a standard way to convey who the user is (an identity token), turning OAuth's authorization machinery into a login mechanism. So when you "log in with Google," you're using OpenID Connect, which rides on OAuth 2.0. Knowing that OAuth is authorization, OIDC adds authentication, and "social login" is OIDC-on-OAuth is exactly the distinction that separates people who understand OAuth from people who've just used it.
Why the flow has two steps (code, then token)
A natural question: why the two-step dance - get a code first, then exchange it for a token? Why not just hand the app the access token directly? The answer reveals OAuth's security thinking.
The redirect back to the app travels through the user's browser, which is a less-secure channel - things passing through it (in the URL) can potentially be exposed (browser history, logs, referrer headers). So OAuth deliberately sends only a temporary, one-time authorization code through that browser redirect - not the actual access token. The code alone is useless to an attacker, because exchanging it for a token requires the app's own secret credentials, which the app sends directly to the authorization server over a secure back-channel, not through the browser.
So the two-step design means: even if someone intercepts the authorization code from the browser redirect, they can't use it without the app's secret, which never travels through the browser. The sensitive access token is only ever obtained through the secure direct exchange. This is a deliberate, elegant security measure - splitting the flow so the vulnerable browser channel only ever carries something useless on its own. Understanding why the code-then-token two-step exists (to keep the token off the insecure browser channel) marks real understanding of OAuth rather than memorized steps.
Different flows for different clients
OAuth 2.0 defines several flows (grant types) for different situations:
- Authorization code flow - the one described above, the standard for web apps (and, with an added protection called PKCE, for mobile and single-page apps). The most secure and most common.
- Client credentials flow - for machine-to-machine access where there's no user involved (a service accessing another service on its own behalf). No user consent step; the app authenticates as itself.
- Other/legacy flows - older flows existed for devices with limited input or simpler scenarios, though some early ones (like the implicit flow) are now discouraged in favor of the authorization code flow with PKCE.
The detail to remember: the authorization code flow is the default and most secure for user-facing apps, and OAuth provides other flows for special cases (notably machine-to-machine via client credentials). You don't need every flow memorized, but knowing OAuth adapts to different client types - and that the authorization code flow (with PKCE for public clients) is the recommended standard - shows current understanding.
OAuth security considerations
OAuth is secure when implemented correctly, but there are real pitfalls:
- Redirect URI validation. The authorization server must strictly validate where it redirects back to, because a flaw here could let an attacker receive the authorization code. Locking down exactly which redirect URIs are allowed for each app is essential.
- Scope minimization. Apps should request only the scopes they need (and users should be wary of apps requesting excessive permissions). An app asking for far more access than it needs is a red flag - the whole point of OAuth is limited access.
- Token protection. Access tokens and especially refresh tokens are powerful credentials - a stolen refresh token can grant lasting access - so they must be stored and transmitted securely (always over HTTPS, guarded at rest).
- Use established providers and libraries. OAuth has subtle details, and implementing an authorization server or client from scratch invites mistakes. The strong recommendation is to use well-established providers and audited libraries so the subtle security details are handled correctly.
These reinforce that OAuth's security comes from careful implementation of its details - which is why, like most security, the advice is to lean on established, audited tools rather than improvising.
A worked example: connecting a calendar app
To ground it all, walk through a concrete case. You sign up for a scheduling app and want it to see your Google Calendar. You click "Connect Google Calendar." The app (client) redirects you to Google (authorization server). At Google, you log in (your password goes to Google, never the app) and see a consent screen: "This app wants to view and manage your calendar." You approve. Google redirects you back to the app with an authorization code. The app's server quietly exchanges that code - plus its own app credentials - with Google for an access token (and a refresh token). Now the app uses the access token to call Google Calendar's API and read your events, limited to the calendar scope you approved. When the access token expires, the app uses the refresh token to get a new one without bothering you. And if you later change your mind, you revoke the app's access in your Google settings - instantly cutting it off, without changing your password.
Every OAuth concept appears in that flow: the four roles, the consent, the code-then-token exchange, scopes (calendar only), access and refresh tokens, and revocability. That single "Connect Google Calendar" click is the whole framework working - and the app never saw your password, got only the calendar access you allowed, and can be revoked anytime. That's delegated authorization delivering exactly what it promises.
Why OAuth matters
OAuth 2.0 is foundational to the modern web because it solves delegated access cleanly:
- It eliminates password sharing. Apps never get your password - a massive security win. You authenticate with the provider, not the third-party app.
- It enables limited, scoped access. Apps get only the specific permissions you grant, not your whole account.
- It's revocable. You can withdraw an app's access anytime, without changing your password.
- It powers the connected ecosystem. "Log in with X," apps integrating with your accounts, services accessing each other's APIs on your behalf - all built on OAuth.
Interview: OAuth comes up in system design around authentication, authorization, and third-party integration. The strong answer explains the problem (granting limited access without sharing passwords), the flow (redirect to authorization server, consent, authorization code, exchange for access token, use token on resource server), and the concepts (scopes for limited permissions, short-lived access tokens, refresh tokens). The senior-level signal is the distinction: OAuth 2.0 is authorization, not authentication, and "Log in with X" actually uses OpenID Connect layered on top. Getting that right shows you understand OAuth deeply rather than just having clicked "Log in with Google."
The bottom line
OAuth 2.0 is a framework for delegated authorization - letting you grant an app limited, specific, revocable access to your resources without sharing your password. It involves four roles (you the resource owner, the client app, the authorization server, the resource server) and a flow where you authenticate and consent at the provider (never giving the app your password), the app receives an authorization code, exchanges it for an access token, and uses that token - scoped to only what you allowed - to access your data. Scopes limit permissions, short-lived access tokens limit exposure, and refresh tokens sustain access revocably.
The crucial distinction: OAuth is authorization, not authentication - and "Log in with X" uses OpenID Connect layered on top to add identity. Understand the flow and that distinction, and OAuth stops being the mysterious thing behind the consent screen.
The single idea to carry away: OAuth replaced "give the app your password" with "tell the provider what to allow, and the app gets a limited, revocable token instead of your credentials." Every piece of the framework - the redirect to the provider, the consent screen, the code-then-token exchange, the scopes, the refresh tokens, the revocability - serves that one goal of safe, limited, password-free delegation. Once you see the framework as the answer to "how do I let an app do some things on my behalf without handing it the keys to everything," the whole design makes sense. We cover authentication, authorization, and security across System Design Fundamentals.
Go deeper
- OAuth (Wikipedia) - the framework and its history.
- OAuth 2.0 - Official site - the authoritative resource on the standard.
- RFC 6749 - The OAuth 2.0 Authorization Framework - the official specification.
- The System Design Primer - authentication and authorization in context.