WEB API's Lesson 20 – OAuth Basics | Dataplexa
Web APIs · Lesson 20

OAuth Basics

Build secure third-party authentication flows that let users log in with their existing accounts.

GitHub handles millions of sign-ins daily without ever seeing a single password. Twitter lets hundreds of thousands of apps post tweets without storing user credentials. Spotify allows playlist apps to access your music library while keeping your login details completely private.

This magic happens through OAuth, a protocol that solved one of the web's thorniest problems: how do you let users grant limited access to their accounts without sharing their actual passwords?

Before OAuth existed, third-party apps had to ask users for their actual username and password to services like Gmail or Facebook. Users had to trust every app developer with their most sensitive credentials. One compromised app meant your entire account was at risk.

The Password Problem OAuth Solved

Picture this scenario from 2005: you want to use a cool new photo-sharing app that can automatically post your pictures to your Flickr account. The app asks for your Flickr username and password. You type them in, hoping the developers are trustworthy.

Now that app has your full Flickr credentials. It can delete your entire photo collection, change your password, or sell your login details to competitors. You have zero control over what it accesses and no way to revoke its access without changing your password.

OAuth flipped this model completely. Instead of sharing passwords, users grant specific permissions to applications through temporary tokens. The photo app gets a token that can only upload images to Flickr, nothing else.

Why OAuth Changed Everything

OAuth treats access like a valet key for your car. The valet gets a key that starts the engine and unlocks the doors, but cannot open your glove compartment or trunk. Your real car key stays safely in your pocket, and you can deactivate the valet key anytime without getting a new car key.

1
OAuth Core Concept
Authorization Framework
Token-Based
Secure Access Delegation
RFC 6749
Industry Standard

The Four OAuth Players

Every OAuth flow involves exactly four parties, each with a specific role. Understanding who does what makes the entire protocol click into place.

The Resource Owner is you, the user. You own the data stored in your Google account, GitHub repositories, or Spotify playlists. You decide who gets access to what parts of your information.

The Client is the third-party application requesting access. This could be a mobile app that wants to post to your social media accounts, or a web service that needs to read your calendar events.

OAuth Role Real-World Example What They Control
Resource Owner You, the user Permission decisions
Client Third-party mobile app Access requests
Authorization Server Google OAuth servers Token generation
Resource Server Google Drive API Protected data

The Authorization Server is where the actual OAuth magic happens. This server belongs to the service provider (Google, GitHub, Twitter) and handles all the permission requests and token generation. When you see that familiar popup asking "Allow this app to access your profile?", you are talking to the authorization server.

The Resource Server stores your actual data and responds to API requests. This might be the same physical server as the authorization server, but conceptually they serve different purposes. The resource server checks every incoming request to ensure it has a valid token with the right permissions.

Authorization Code Flow Step by Step

The most common OAuth flow is called Authorization Code Grant. This is what happens when you click "Sign in with Google" on a website and get redirected through that familiar popup.

The APIForge Security team needs to add Google sign-in to their developer dashboard. Users should be able to log in with their existing Google accounts instead of creating yet another username and password.

1. Redirect to Google
2. User authorizes
3. Return with code
4. Exchange for token
5. Access user data

Step one happens when a user clicks the "Sign in with Google" button on APIForge's login page. The browser immediately redirects to Google's authorization server with a specially crafted URL containing the permissions APIForge needs.

# WHAT: APIForge redirects user to Google OAuth server
GET https://accounts.google.com/oauth/authorize
  ?client_id=apiforge-client-id-here
  &redirect_uri=https://apiforge.com/auth/callback
  &scope=openid profile email
  &response_type=code
  &state=random-security-token-xyz123

Google shows the user a permission screen listing exactly what APIForge wants access to: their basic profile information and email address. The user can approve or deny this request. If they approve, Google redirects back to APIForge with a special authorization code.

HTTP/1.1 302 Found Location: https://apiforge.com/auth/callback ?code=auth_code_abc123xyz &state=random-security-token-xyz123 # User is redirected back to APIForge with: # - Authorization code: auth_code_abc123xyz # - State parameter: random-security-token-xyz123 (prevents CSRF attacks) # - This code expires in 10 minutes and can only be used once

What just happened?

APIForge sent the user to Google with a request for specific permissions. Google asked the user "Do you want APIForge to see your profile and email?" The user clicked yes, so Google sent them back to APIForge with a temporary authorization code.

Try this: Look at any "Sign in with Google" flow on the web and notice the URL parameters when you get redirected to Google's servers.

Now APIForge has an authorization code, but this is not the final access token yet. The authorization code is like a voucher that can be exchanged for the real token. This exchange happens server-to-server, never in the user's browser.

# WHAT: APIForge backend exchanges authorization code for access token
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code=auth_code_abc123xyz
&redirect_uri=https://apiforge.com/auth/callback
&client_id=apiforge-client-id-here
&client_secret=super-secret-key-never-exposed
HTTP/1.1 200 OK Content-Type: application/json { "access_token": "ya29.a0AfH6SMD...", "expires_in": 3600, "refresh_token": "1//04...", "scope": "openid profile email", "token_type": "Bearer", "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." }

What just happened?

APIForge's backend server proved to Google that it legitimately obtained the authorization code by including the client secret. Google responded with an access token that can make API calls, plus a refresh token for getting new access tokens later.

Try this: Notice how the client secret never touches the user's browser - this prevents malicious JavaScript from stealing it.

Using Access Tokens

Access tokens are the whole point of OAuth. These tokens let APIForge make API calls on behalf of the user without ever knowing their password. Each token comes with a specific scope defining exactly what it can and cannot do.

Now that APIForge has an access token with profile and email permissions, it can fetch the user's basic information to create their account in the APIForge system.

# WHAT: APIForge uses access token to get user's Google profile data
GET https://www.googleapis.com/oauth2/v2/userinfo
Authorization: Bearer ya29.a0AfH6SMD...
Accept: application/json
HTTP/1.1 200 OK Content-Type: application/json { "id": "108367316387462080449", "email": "developer@example.com", "verified_email": true, "name": "Alex Martinez", "given_name": "Alex", "family_name": "Martinez", "picture": "https://lh3.googleusercontent.com/a/default-user=s96-c" }

What just happened?

APIForge sent its access token in the Authorization header using Bearer authentication. Google verified the token and returned the user's profile information. APIForge can now create a user account with this data.

Try this: Notice that the access token acts like a temporary password that only works for specific operations the user approved.

Access tokens have built-in expiration dates, usually between 1 hour and 24 hours. This limits the damage if a token gets compromised. When tokens expire, applications use refresh tokens to get new access tokens without bothering the user again.

Different OAuth providers handle token expiration differently. GitHub tokens last indefinitely until revoked, while Google tokens expire every hour. Slack tokens last for 12 hours, and Twitter tokens expire after 2 hours.

Token Security Best Practices

Store access tokens like passwords - encrypt them in your database, never log them, and transmit them only over HTTPS. Set up monitoring to detect unusual token usage patterns that might indicate compromise.

OAuth Scopes and Permissions

Scopes are OAuth's permission system. Instead of giving apps unlimited access to user accounts, OAuth lets users grant specific permissions for specific operations. This principle of least privilege keeps user data safer.

When Spotify's mobile app requests OAuth permissions, it asks for scopes like user-read-private to see your profile, user-read-playback-state to know what you are currently listening to, and user-modify-playback-state to control your music playback.

A playlist management app might only request playlist-read-private and playlist-modify-private scopes. It cannot access your listening history, friend lists, or account settings because those permissions require different scopes.

OAuth Concept What it does APIForge use case
Authorization Code Temporary voucher for access token User approves, Google sends code to APIForge
Access Token Proves permission to access resources APIForge calls Google APIs with Bearer token
Refresh Token Gets new access tokens without user APIForge refreshes expired tokens automatically
Scope Defines what permissions token has APIForge requests only profile and email access
State Parameter Prevents cross-site request forgery APIForge verifies user came from legitimate flow

Each OAuth provider defines their own scope names and granularity. Google uses descriptive scopes like https://www.googleapis.com/auth/drive.readonly for read-only Drive access. GitHub uses simpler names like repo for repository access and user for profile information.

The APIForge Backend team wants to build a feature that automatically creates GitHub repositories for new API projects. They need to request the repo scope, which allows creating, reading, updating, and deleting repositories.

// WHAT: APIForge requests GitHub OAuth with repository permissions
const githubAuthUrl = new URL('https://github.com/login/oauth/authorize');
githubAuthUrl.searchParams.set('client_id', 'apiforge_github_client_id');
githubAuthUrl.searchParams.set('redirect_uri', 'https://apiforge.com/github/callback');
githubAuthUrl.searchParams.set('scope', 'repo user:email');
githubAuthUrl.searchParams.set('state', generateSecureRandomString());

// Redirect user to GitHub for authorization
window.location.href = githubAuthUrl.toString();
# User sees GitHub authorization page: "APIForge would like permission to: ✓ Access your public and private repositories ✓ Know which resources you can access ✓ Access your email addresses (read-only) [Authorize APIForge] [Cancel]" # After approval, user redirected to: # https://apiforge.com/github/callback?code=abc123&state=xyz789

What just happened?

APIForge requested specific GitHub permissions: full repository access and email address access. GitHub showed the user exactly what permissions were being requested in plain English. The user could see that APIForge would be able to create and manage repositories on their behalf.

Try this: Look at the OAuth permission screens for different services - notice how they translate technical scope names into user-friendly descriptions.

Other OAuth Grant Types

Authorization Code flow works perfectly for web applications, but different types of applications need different OAuth approaches. Mobile apps cannot securely store client secrets, and single-page JavaScript apps run entirely in browsers with no backend server.

The Implicit Grant was designed for JavaScript apps running in browsers. Instead of exchanging an authorization code for tokens, the authorization server returns access tokens directly in the URL fragment. This flow is now considered less secure and PKCE is preferred.

PKCE (Proof Key for Code Exchange) solves the mobile app problem by adding a dynamically generated secret to the authorization code flow. The app creates a random code verifier, sends a hashed version to the authorization server, then proves it has the original during token exchange.

Traditional Web Apps

Use Authorization Code flow with client secrets stored securely on backend servers. The browser never sees sensitive credentials.

Mobile & SPA Apps

Use Authorization Code with PKCE. No client secrets needed because the PKCE challenge provides security through cryptographic proof.

The APIForge Frontend team is building a React dashboard that needs to access user data directly from the browser. They cannot use client secrets because any JavaScript code is visible to users, so they implement PKCE flow instead.

Client Credentials Grant handles server-to-server authentication when no user is involved. This is how APIForge's backend services authenticate with each other or with external APIs using their own credentials rather than user permissions.

Security Evolution

OAuth 2.0 initially had security gaps that real-world usage exposed. OAuth 2.1 tightens these by requiring PKCE for all public clients, deprecating implicit flow, and mandating exact redirect URI matching. Always implement the latest security recommendations, not just the minimum spec requirements.

Refresh tokens deserve special attention because they are long-lived credentials. Unlike access tokens that expire quickly, refresh tokens can last weeks or months. Some providers issue new refresh tokens with each refresh to enable token rotation and improve security.

When APIForge's scheduled background jobs need to sync data from user's connected services, they use stored refresh tokens to obtain fresh access tokens without interrupting the user. This enables seamless integration experiences.

# WHAT: APIForge background job refreshes expired access token  
POST https://oauth2.googleapis.com/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token=1//04refresh_token_here
&client_id=apiforge-client-id
&client_secret=super-secret-never-exposed
HTTP/1.1 200 OK Content-Type: application/json { "access_token": "ya29.a0NewAccessToken...", "expires_in": 3600, "token_type": "Bearer", "scope": "openid profile email" }

What just happened?

APIForge used a stored refresh token to get a new access token without involving the user. The response includes a fresh access token with the same permissions as before. Some providers also return a new refresh token for additional security.

Try this: Set up token refresh logic in your apps to handle expired access tokens gracefully - users should never see authentication errors during normal usage.

Common OAuth Pitfalls

OAuth seems straightforward until you implement it in production. Real-world OAuth flows break in subtle ways that are not obvious from reading the specification. Understanding these failure modes saves hours of debugging.

The most common mistake is not validating the state parameter properly. This parameter prevents CSRF attacks where malicious sites trick users into authorizing access for attacker-controlled applications. Every OAuth request must include a unique, unpredictable state value.

Redirect URI validation trips up many developers. OAuth providers require exact matches between the redirect URI in your client configuration and the one in authorization requests. https://apiforge.com/callback does not match https://apiforge.com/callback/ - that trailing slash matters.

OAuth Security Checklist

Always validate state parameters, use HTTPS for all OAuth endpoints, store client secrets securely, implement proper token storage with encryption, set reasonable token expiration times, and monitor for suspicious authorization patterns. Never log access tokens or refresh tokens in plain text.

Token storage presents another challenge. Access tokens are sensitive credentials that should be encrypted at rest and transmitted only over secure connections. Many applications make the mistake of storing tokens in browser localStorage, which exposes them to XSS attacks.

Scope creep is a business problem masquerading as a technical issue. Applications tend to request broad permissions they might need someday instead of asking for minimal scopes and requesting additional permissions when needed. Users are more likely to authorize narrow, clearly justified permission requests.

Error handling in OAuth flows requires special attention because authorization can fail at multiple points: user denial, invalid scopes, server errors, network timeouts, and token exchange failures all need graceful handling with appropriate user messaging.

Quiz

1. The APIForge Security team needs to explain OAuth's main benefit to stakeholders. What is the primary problem OAuth solves?

2. In the OAuth authorization code flow, what is the purpose of the authorization code that gets returned to APIForge after user approval?

3. APIForge's background jobs need to sync data from users' connected Google accounts, but access tokens expire after one hour. What should they do when tokens expire?

Up Next
JWT Authentication
APIForge explores stateless authentication tokens that carry user information and permissions in self-contained packages.