Skip to content
OAuth 2.0 Flows: Delegated Authorization Made Practical 4 min

OAuth 2.0 Flows: Delegated Authorization Made Practical

SD
ScaleDojo
May 11, 2026
4 min read1,003 words
OAuth2 Flows: Delegated Authorization Made Practical

The Problem That Created OAuth

In 2006, Twitter developer Blaine Cook was building an API for third-party apps. The only option at the time was asking users for their Twitter password directly. Yelp, a major Twitter partner, ended up storing millions of user passwords just to make its integration work. When Yelp had a security incident, every one of those users' Twitter accounts was compromised too. Cook, along with engineers from Google and other companies, designed OAuth to fix this: let users grant limited access to an app without ever handing over their password. That fix became the foundation for the OAuth 2.0 flows developers rely on today.

Today, every "Sign in with Google/GitHub/Facebook" button runs on OAuth 2.0 authentication, and over 2 billion OAuth authorizations happen daily. If you're doing any kind of system design work involving third-party access or API platforms, understanding these flows isn't optional.

The Four OAuth2 Roles

OAuth2 Actors:

  Resource Owner (User)
  'I own my Google photos'
       |
       | 1. 'Allow PhotoEditor to access my photos?'
       | 2. 'Yes, allow read-only access'
       v
  Authorization Server (Google)
  'I verify the user and issue tokens'
       |
       | 3. Issues access_token + refresh_token
       v
  Client (PhotoEditor App)
  'I want to access the user's photos'
       |
       | 4. GET /photos  Authorization: Bearer <token>
       v
  Resource Server (Google Photos API)
  'I serve the photos if the token is valid'

Authorization Code Flow (Web Apps)

This is the flow most people mean when they say "OAuth," and it's the one to reach for whenever your app has a backend that can keep a secret.

Authorization Code Flow (Most Secure):

  User        Client (Backend)       Auth Server        Resource Server
   |               |                     |                    |
   |--1. Click 'Login with Google'------->|                    |
   |               |                     |                    |
   |<--2. Redirect to Google login--------|                    |
   |               |                     |                    |
   |--3. User logs in + consents--------->|                    |
   |               |                     |                    |
   |<--4. Redirect with auth CODE---------|                    |
   |               |                     |                    |
   |--5. Send code to YOUR backend------->|                    |
   |               |                     |                    |
   |               |--6. Exchange code--->|                    |
   |               |    + client_secret   |                    |
   |               |                     |                    |
   |               |<--7. access_token----|                    |
   |               |    + refresh_token   |                    |
   |               |                     |                    |
   |               |--8. GET /photos -----|--Bearer token----->|
   |               |                     |                    |
   |               |<---------photos-----|----photos----------||
   |<--9. Render photos------------------|                    |

  Security: access_token NEVER reaches the browser.
  The auth code is single-use and expires in 60 seconds.

PKCE Flow (Mobile/SPAs)

The OAuth authorization code flow assumes the client can hold a secret. Mobile apps and single-page apps can't, since anyone can decompile a binary or read a bundled JS file and pull the secret straight out. PKCE closes that gap.

Authorization Code + PKCE (Proof Key for Code Exchange):

  Problem: Mobile apps and SPAs cannot store a client_secret safely.
           Anyone can decompile an app and extract the secret.

  Solution: Replace static secret with dynamic proof.

  Before redirect:
    1. Generate random code_verifier (43-128 chars)
    2. Hash it: code_challenge = SHA256(code_verifier)
    3. Send code_challenge with auth request

  After redirect (exchanging code for token):
    4. Send original code_verifier
    5. Auth server hashes it and compares with stored code_challenge
    6. Match? Issue token. No match? Reject.

  Why this works:
    - Attacker intercepts auth code? Useless without code_verifier
    - code_challenge is a hash, cannot reverse to get code_verifier
    - Different code_verifier for every auth attempt

  PKCE is now recommended for ALL OAuth2 flows (RFC 7636).

When to Use Which Flow

Picking the right OAuth 2.0 flow comes down to one question: can this client keep a secret? The table below is a decent starting point, and it's worth revisiting alongside your broader low-level design decisions, since auth touches almost every service boundary.

OAuth2 Flow Selection Guide:

  Your Application         Flow                    Why
  --------------------     ---------------------   --------------------------
  Web app with backend     Authorization Code      Backend stores secrets safely
  SPA (React, Vue)         Auth Code + PKCE        No safe secret storage
  Mobile app (iOS/Android) Auth Code + PKCE        App binary can be decompiled
  Server-to-server (APIs)  Client Credentials      No user involved
  CLI tool                 Device Authorization    No browser redirect possible
  Microservice-to-service  Client Credentials      Service identity, not user

  DEPRECATED (never use):
  - Implicit Flow: token in URL fragment, easily leaked
  - Resource Owner Password: app receives user's password directly

Common OAuth2 Mistakes

  • Not validating the state parameter, which enables CSRF attacks. Always generate a random state, store it in session, and verify it on callback.

  • Using the Implicit flow, deprecated since 2019. It exposes tokens in URL fragments and browser history.

  • Requesting too many scopes. Ask for the minimum permissions needed, so "scope=read:email" rather than "scope=admin."

  • Skipping PKCE for SPAs. Authorization Code without PKCE for public clients is vulnerable to code interception.

  • Storing tokens in localStorage, which is vulnerable to XSS. Use HTTP-only secure cookies instead.

  • Not validating redirect_uri. Open redirect attacks can steal auth codes, so whitelist exact redirect URIs rather than pattern-matching them.

Most of these mistakes also show up at the API boundary layer, right where you'd be deciding between an API gateway, BFF, or another protocol pattern. Token validation and scope checks are usually best centralized there rather than duplicated in every service.

Interview Tip

In system design interviews, OAuth2 comes up when designing social login, third-party integrations, or API platforms. Draw the Authorization Code flow with all four actors (user, client, auth server, resource server). Emphasize that the access token never reaches the browser in the standard flow. Mention PKCE as the modern standard for mobile and SPAs. If you're designing an API platform, explain how you'd implement the Client Credentials flow for service-to-service auth. The phrase interviewers want to hear: "delegated authorization without credential sharing."

If you're building up to these interviews, it's worth pairing this with broader prep resources, like this roundup of system design learning platforms, so OAuth doesn't end up as an isolated fact you memorized rather than a pattern you actually understand.

Key Takeaway

OAuth2 enables delegated authorization: users grant limited permissions to apps without sharing passwords. Use the Authorization Code flow for web apps, add PKCE for SPAs and mobile, and use Client Credentials for machine-to-machine calls. Never use the Implicit flow. Always validate state parameters and restrict redirect URIs. These are the OAuth 2.0 best practices that separate a secure implementation from one waiting to be exploited.

Enjoyed this article?

Share it with your network to help others level up their system design skills.

Discussion0

Join the Discussion

Sign in to leave comments, reply to others, or like insights.

Sign In to ScaleDojo

No comments yet. Be the first to start the thread!

Related Articles

Enjoyed this content?

Your support keeps us creating free resources

We put a lot of hours into researching and writing these guides. If it helped you, consider buying us a coffee. Every bit goes toward keeping ScaleDojo's content free and growing.

$

One-time payment via Stripe. ScaleDojo account required.

ScaleDojo Logo
Initializing ScaleDojo