How OAuth 2.0 Works: Delegated Authorization Explained

Every time you click "Sign in with Google" or let a third-party app access your GitHub repositories, you are using OAuth 2.0. It is the authorization framework that lets you grant limited access to your accounts on one service to another service — without ever sharing your password.

OAuth 2.0 is defined in RFC 6749 (2012) and has become the de facto standard for delegated authorization on the web. Understanding how it works is essential for anyone building or securing web applications, APIs, or mobile apps.

The Problem: Why Not Just Share Passwords?

Before OAuth, the way to let a third-party application access your data was to give it your username and password. If you wanted a printing service to access your photos stored on another site, you would hand over your credentials. This had severe problems:

OAuth solves this by introducing an authorization layer that separates the role of the client (the app that wants access) from the resource owner (you). Instead of sharing credentials, the resource owner grants the client a token with specific, limited permissions.

The Four Roles

OAuth 2.0 defines four distinct roles that interact during an authorization flow:

In practice, the authorization server and resource server are often operated by the same organization (Google, GitHub, etc.), but they are logically separate components with different responsibilities.

The Authorization Code Flow

The Authorization Code grant is the most common and most secure OAuth 2.0 flow. It is used by web applications and mobile apps to obtain access tokens. Here is how it works, step by step:

User (Browser) Client App Auth Server Resource Server 1. Click "Sign in" 2. Redirect to Auth Server 3. User logs in + consents 4. Redirect with authorization code 5. Forward code to client 6. Exchange code + secret for tokens 7. Access token + refresh token 8. API request with access token 9. Protected resource data Authorization Code grant Token exchange API access

Let us walk through each step:

  1. The user clicks "Sign in" on the client application. The client constructs an authorization URL pointing to the authorization server.
  2. The client redirects the user's browser to the authorization server. The redirect URL includes the client ID, requested scopes, a redirect URI, and a random state parameter (for CSRF protection).
  3. The user authenticates directly with the authorization server (enters their Google password, for example) and sees a consent screen listing the permissions the client is requesting. The user's password is never exposed to the client application.
  4. The authorization server redirects back to the client's redirect URI with a short-lived authorization code in the URL query string.
  5. The browser follows the redirect, delivering the authorization code to the client's backend server.
  6. The client's server exchanges the authorization code for tokens by making a direct server-to-server POST request to the authorization server's token endpoint. This request includes the client's secret, which proves the client's identity.
  7. The authorization server returns an access token (and optionally a refresh token). The authorization code is now consumed and cannot be reused.
  8. The client uses the access token to make API requests to the resource server, typically in the Authorization: Bearer <token> header.
  9. The resource server validates the token and returns the requested data.

The key security insight: the authorization code is exchanged via the user's browser (the "front channel"), but the token exchange happens directly between the client server and the authorization server (the "back channel"). The access token never passes through the browser. This entire flow runs over TLS/HTTPS, so all data in transit is encrypted.

Tokens: Access Tokens and Refresh Tokens

OAuth 2.0 uses two types of tokens:

Access tokens are credentials that the client presents to the resource server to access protected resources. They are typically short-lived (minutes to hours). An access token can be an opaque string (a random identifier that the resource server looks up in a database) or a self-contained token like a JSON Web Token (JWT) that carries its own claims and can be verified without a database lookup.

Refresh tokens are long-lived credentials used to obtain new access tokens after the current one expires. Unlike access tokens, refresh tokens are only ever sent to the authorization server — never to the resource server. This limits their exposure. If an access token is leaked, the damage is time-limited. If a refresh token is leaked, the authorization server can revoke it.

Token Lifecycle Access Token (1h) Refresh Access Token (1h) Refresh Access Token... Refresh Token (days/months — sent only to auth server) Short-lived access tokens limit blast radius if leaked. Long-lived refresh tokens stay on the server, never reach the resource server. Refresh tokens can be rotated: each use issues a new refresh token and invalidates the old one. If a refresh token is stolen and used, rotation detects the anomaly and revokes the family.

Scopes: Limiting What Access Tokens Can Do

Scopes define the boundaries of access that the client is requesting. When the client redirects the user to the authorization server, it includes a scope parameter listing the permissions it needs. The user sees these scopes on the consent screen and can choose to grant or deny them.

Scopes are strings defined by the resource server. There is no universal standard for scope naming, but some common patterns exist:

The principle of least privilege applies: clients should request only the scopes they need. A photo printing service needs read access to your photos, not write access to your email. Users have learned to be suspicious of apps requesting broad scopes.

Grant Types

OAuth 2.0 defines several grant types (also called flows) for different use cases. Each represents a different way for the client to obtain an access token.

OAuth 2.0 Grant Types Authorization Code + PKCE Use: Web apps, mobile apps, SPAs User interaction: Yes (login + consent) Client secret: Optional (PKCE replaces it) Security: Highest — code verifier proves the client that started the flow is the one exchanging the code Client Credentials Use: Service-to-service (no user) User interaction: None Client secret: Required Security: Client authenticates itself directly. No user context — the token represents the app, not a person Device Code Use: TVs, CLI tools, IoT (no browser) User interaction: Yes (on separate device) Client secret: Optional Security: User visits a URL on their phone, enters a code, and authorizes the device. Device polls until authorized Implicit (Deprecated) Use: Was used for browser-only SPAs User interaction: Yes Client secret: None Security: Insecure — token returned in URL fragment, exposed to browser history and referrer headers. Use Auth Code + PKCE instead Recommendation: Use Authorization Code + PKCE for all new applications (RFC 7636, OAuth 2.1 draft)

Authorization Code with PKCE

PKCE (Proof Key for Code Exchange, pronounced "pixy," defined in RFC 7636) is an extension to the authorization code flow designed to protect against authorization code interception attacks. It is now recommended for all OAuth clients — not just mobile apps where it originated.

With PKCE, the client generates a random code_verifier and derives a code_challenge from it (typically using SHA-256). The code challenge is sent in the initial authorization request, and the code verifier is sent when exchanging the authorization code for tokens. The authorization server verifies that they match, proving that the client that initiated the flow is the same one completing it.

This defeats attacks where a malicious app intercepts the authorization code (via a custom URL scheme on mobile, for example) but cannot complete the exchange because it does not know the code verifier.

Client Credentials

The client credentials grant is for machine-to-machine communication where no user is involved. The client authenticates directly with the authorization server using its client ID and client secret, and receives an access token. There is no browser redirect, no user consent, and no authorization code.

This is used for backend services that need to access APIs on their own behalf — for example, a cron job that reads analytics data, or a microservice calling another microservice.

Device Code

The device code grant (RFC 8628) is designed for devices that lack a browser or have limited input capabilities — smart TVs, game consoles, CLI tools, and IoT devices. The device displays a URL and a short user code. The user visits the URL on their phone or computer, enters the code, and authorizes the device. Meanwhile, the device polls the authorization server until authorization is granted.

You see this flow when logging into streaming apps on a smart TV: the TV shows "Visit example.com/activate and enter code ABCD-EFGH."

OpenID Connect: Adding Authentication

OAuth 2.0 is an authorization framework — it answers "what is this app allowed to do?" but does not inherently answer "who is this user?" OpenID Connect (OIDC) is a thin identity layer built on top of OAuth 2.0 that adds authentication — it tells the client who the user is.

The key difference: OAuth alone gives you an access token to call APIs. OpenID Connect additionally gives you an ID token — a JWT that contains claims about the authenticated user (their name, email, unique identifier, etc.). The ID token is signed by the authorization server (called the OpenID Provider in OIDC terminology) and can be verified by the client.

To use OpenID Connect, the client includes the openid scope in the authorization request. The authorization server then returns an ID token alongside the access token. Common additional scopes include profile (name, picture) and email.

"Sign in with Google," "Sign in with Apple," and "Log in with GitHub" all use OpenID Connect. When you see "This app wants to access your name and email," that is an OIDC consent screen. The application receives an ID token confirming your identity and (optionally) an access token to call Google/Apple/GitHub APIs on your behalf.

Token Introspection and Revocation

Token introspection (RFC 7662) allows a resource server to query the authorization server about a token: "Is this token valid? What scopes does it have? When does it expire? Who is it for?" This is necessary when tokens are opaque strings — the resource server cannot decode them locally and must ask the authorization server. Self-contained JWTs can be validated locally without introspection, but introspection can still be used to check revocation status.

Token revocation (RFC 7009) allows a client to notify the authorization server that a token is no longer needed and should be invalidated immediately. This is what happens when you click "Sign out" — the client revokes the access and refresh tokens so they cannot be used even if intercepted. Revocation is especially important for refresh tokens, which are long-lived.

The Token Request in Detail

The token exchange (step 6 in the authorization code flow) is a standard HTTP POST request. Here is what it looks like:

POST /oauth/token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https://app.example.com/callback
&client_id=s6BhdRkqt3
&client_secret=7Fjfp0ZBr1KtDRbnfVdmIw
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

The authorization server validates the code, verifies the client's identity (via the secret or PKCE verifier), and returns a JSON response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA",
  "scope": "read:user email",
  "id_token": "eyJhbGciOiJSUzI1NiIs..."
}

The access_token and id_token here are JWTs — base64url-encoded JSON payloads with a cryptographic signature. The access token is presented to resource servers in the Authorization header. The ID token is consumed by the client to learn who the user is.

Security Best Practices

OAuth 2.0 is a framework with many moving parts. Implementing it incorrectly creates vulnerabilities. These are the critical security practices:

Real-World Example: Sign in with Google

When you click "Sign in with Google" on a website, here is exactly what happens:

  1. The website redirects you to https://accounts.google.com/o/oauth2/v2/auth with parameters specifying the client ID (registered in Google Cloud Console), requested scopes (openid email profile), and a redirect URI back to the website.
  2. Google shows you a login screen (if not already signed in) and a consent screen listing what the website wants to access.
  3. You click "Allow." Google redirects your browser back to the website's redirect URI with an authorization code.
  4. The website's server exchanges the code at https://oauth2.googleapis.com/token using its client ID and client secret.
  5. Google returns an access token, refresh token, and ID token (a JWT containing your Google user ID, name, email, and profile picture).
  6. The website reads the ID token to learn who you are, creates or updates your account, and sets a session cookie.
  7. If the website needs ongoing access to Google APIs (like reading your Google Calendar), it stores the refresh token and uses it to get new access tokens as needed.

The entire authentication flow happens over HTTPS, your Google password is never exposed to the website, and you can revoke the website's access at any time from your Google Account settings without changing your password.

OAuth 2.0 and Network Infrastructure

While OAuth is an application-layer protocol, it depends heavily on the network infrastructure covered throughout this site. Every OAuth flow requires reliable, secure network connectivity:

This is defense in depth: OAuth provides application-layer authorization, TLS provides transport-layer encryption, RPKI provides routing-layer verification, and each layer protects against failures in the others.

See It in Action

OAuth 2.0 authorization servers run on infrastructure routed through BGP like everything else on the internet. You can explore the networks that power major identity providers:

See BGP routing data in real time

Open Looking Glass
More Articles
How JWT Works: JSON Web Tokens Explained
How JWKS and JWT Validation Work
What is BGP? The Internet's Routing Protocol Explained
What is an Autonomous System (AS)?
What is a BGP Looking Glass?
How to Look Up an IP Address's BGP Route