BytePane

What Is OAuth? Authentication & Authorization Explained

Security18 min read

The Protocol Behind Every “Sign In With” Button

Every time you click “Sign in with Google,” “Continue with GitHub,” or “Connect Spotify,” OAuth is running under the hood. Per industry data from arcade.dev's 2025 OAuth Adoption & Security Trends report, 92% of enterprises now use OAuth 2.0 within their authentication infrastructure. PKCE — the security extension that makes OAuth safe for mobile and SPA apps — saw a 178% growth in implementation over two years.

Despite its ubiquity, OAuth is frequently misunderstood. Developers conflate it with authentication (it's authorization). They confuse OAuth 1.0a with 2.0 (completely different designs). They implement it insecurely by storing tokens in localStorage or skipping PKCE. And they use it when they should use OpenID Connect — or vice versa.

This article builds a clear mental model: what OAuth is, what problem it solves, how it evolved from 1.0a to 2.0 to 2.1, the difference between OAuth and authentication, the grant types that matter in 2026, and how real systems like “Sign in with Google” wire it together. For the full technical deep-dive into OAuth 2.0 flows with code, see BytePane's OAuth 2.0 step-by-step guide.

Key Takeaways

  • OAuth is authorization, not authentication. It grants an app access to specific resources — it does not verify who the user is. OpenID Connect (OIDC) adds identity on top of OAuth 2.0.
  • OAuth 2.0 (RFC 6749, 2012) replaced OAuth 1.0a's complex per-request HMAC signing with bearer tokens over HTTPS. Simpler to implement, but requires HTTPS to be secure.
  • 92% of enterprises use OAuth 2.0 in their authentication infrastructure (arcade.dev 2025 OAuth Adoption Report). PKCE implementation grew 178% in two years.
  • In 2026, the Authorization Code + PKCE flow is the correct choice for virtually all user-facing apps. The implicit flow is formally deprecated (RFC 9700, 2024).
  • OAuth 2.1 (draft) consolidates best practices: mandatory PKCE, no implicit grant, no Resource Owner Password Credentials, exact redirect URI matching.

The Problem OAuth Solves: Delegated Authorization Without Sharing Passwords

Before OAuth existed, the standard approach to third-party integrations was credential sharing. To connect Yelp to your Gmail contacts in 2007, Yelp asked for your Gmail password, logged in as you, and scraped your contact list. Twitter did the same to suggest people you might follow. This anti-pattern was widespread — and catastrophically insecure:

  • The third-party app had unlimited access — not just what it needed
  • Revoking access required changing your password, breaking every other service
  • If the third-party was breached, your primary account was compromised
  • You had no visibility into what the app actually did with your credentials

OAuth was designed by Blaine Cook and Chris Messina in 2006, initially at Twitter, specifically to solve this problem. The core insight: instead of sharing credentials, issue a scoped, time-limited token that represents specific permissions. The Yelp app gets a token that says “read contacts only” — not your password, not access to your email, not access to your calendar. You can revoke that token at any time without touching your password.

OAuth Is Authorization — Not Authentication

This distinction trips up even experienced developers. Let's be precise:

ConceptQuestion It AnswersProtocolOutput
Authentication (AuthN)“Who are you?”OpenID Connect (OIDC)ID Token (JWT with user claims)
Authorization (AuthZ)“What are you allowed to do?”OAuth 2.0Access Token (scoped permissions)

OAuth 2.0 (RFC 6749) explicitly states in its introduction: “OAuth 2.0 is an authorization framework that enables applications to obtain limited access to user accounts on an HTTP service.” There is no user identity in an OAuth access token — only scopes and permissions.

OpenID Connect (OIDC) adds the identity layer on top of OAuth 2.0. OIDC is a thin identity protocol built as an OAuth 2.0 extension: it adds an openid scope, an ID token (a JWT containing user identity claims like sub, email, name), and a /userinfo endpoint. “Sign in with Google” is OIDC — OAuth 2.0 is the transport, OIDC is the identity assertion riding on it.

OAuth scopes vs OIDC scopes — what you get in each token
# OAuth 2.0 scopes — control what resources the app can access
scope=read:emails write:calendar

# Access token payload (what the resource server checks)
{
  "iss": "https://auth.google.com",
  "aud": "api.yourapp.com",
  "sub": "1234567890",           # opaque user ID
  "scope": "read:emails write:calendar",
  "exp": 1746300000,
  "iat": 1746296400
}
# Notice: no email, no name. Just scopes and a user ID.

# OIDC scopes — additionally request identity claims
scope=openid profile email

# ID token payload (what YOUR app reads to know who logged in)
{
  "iss": "https://accounts.google.com",
  "aud": "your-client-id.apps.googleusercontent.com",
  "sub": "1234567890",           # stable user identifier
  "email": "[email protected]",
  "name": "Jane Doe",
  "picture": "https://...",
  "email_verified": true,
  "exp": 1746300000,
  "iat": 1746296400,
  "nonce": "abc123"              # OIDC replay protection
}
# ID token is for YOUR app to read. Never send it to resource servers.

OAuth 1.0a vs OAuth 2.0: What Changed and Why

OAuth 1.0 was published as RFC 5849 in April 2010. OAuth 2.0 (RFC 6749) replaced it in October 2012. They are completely different protocols — incompatible, with a completely different security model. Most of what you encounter today is OAuth 2.0, but understanding what changed explains why the protocol works the way it does.

AspectOAuth 1.0a (RFC 5849)OAuth 2.0 (RFC 6749)
Security modelHMAC-SHA1 signature on every requestBearer tokens over HTTPS
Transport dependencyWorks over HTTP (signatures provide integrity)Requires HTTPS (tokens are secrets)
Implementation complexityHigh — request signing requires precise parameter ordering, percent-encoding, timestamp+nonce managementLow — attach the token in the Authorization header
Client typesOne flow, all clientsMultiple grant types for web, SPA, mobile, M2M
Token storageConsumer key + secret (persistent)Short-lived access tokens + refresh tokens
Current statusLegacy — only Twitter API v1 still used it (now retired)Universal standard — Google, GitHub, Stripe, Facebook, Microsoft

OAuth 1.0a's signature approach had a theoretical advantage: token theft mid-transit couldn't be exploited because the attacker also needed the signing secret. But the complexity was enormous — many developers implemented it incorrectly, and “works over plain HTTP” is less relevant now that HTTPS is effectively universal (99% of Chrome browsing is HTTPS). OAuth 2.0's bet on HTTPS as the security baseline paid off.

OAuth 2.0 Grant Types: Choosing the Right Flow

A grant type defines how a client obtains an access token. OAuth 2.0 defined four in RFC 6749; subsequent RFCs added more. In 2026, two are in active use, one is used for specific device scenarios, and two are formally deprecated:

Authorization Code + PKCE — Use for all user-facing apps

The user is redirected to the authorization server, authenticates, and grants permission. The server issues a short-lived authorization code and redirects back to the client. The client exchanges the code for an access token via a server-to-server request. PKCE (RFC 7636) prevents code interception by requiring the client to prove it initiated the request.

Use for: Web apps, SPAs, mobile apps, desktop apps — anything with a human user and a redirect capability.

Client Credentials — Use for machine-to-machine

The client authenticates directly with the authorization server using its own client ID and secret. No user involved, no redirect. Gets an access token for its own operations.

Use for: Background services, microservice-to-microservice calls, CI/CD pipelines, cron jobs.

Device Authorization (RFC 8628) — Use for input-constrained devices

The device displays a short code and a URL. The user goes to that URL on another device (phone, laptop), enters the code, and approves. The original device polls for the token.

Use for: Smart TVs, game consoles, CLI tools, IoT devices — anything without a browser.

Implicit — Deprecated (RFC 9700, 2024). Never implement.

Returned access tokens directly in the URL fragment (#access_token=...), exposing them to browser history, referrer headers, and XSS. SPAs should use Authorization Code + PKCE instead.

Resource Owner Password Credentials — Deprecated (OAuth 2.1). Never implement.

Required the user to enter credentials directly into the third-party app, which then exchanged them for tokens. This defeats OAuth's core purpose — not sharing passwords — entirely.

How “Sign in with Google” Actually Works

“Sign in with Google” is OIDC (OpenID Connect) layered on OAuth 2.0. Here is the complete flow, annotated with which parts are OAuth and which are OIDC:

Google Sign-In — OIDC Authorization Code + PKCE flow
# 1. User clicks "Sign in with Google" on your app.
#    Your app generates PKCE params and redirects the browser:

GET https://accounts.google.com/o/oauth2/v2/auth
  ?response_type=code
  &client_id=YOUR_CLIENT_ID.apps.googleusercontent.com
  &redirect_uri=https://yourapp.com/auth/callback
  &scope=openid profile email        ← "openid" = OIDC; "profile email" = user claims
  &state=CSRF_TOKEN                  ← OAuth CSRF protection
  &code_challenge=SHA256_HASH        ← PKCE challenge
  &code_challenge_method=S256

# 2. Google authenticates the user (shows login form + consent screen).
#    Redirects back to your app with an authorization code:

GET https://yourapp.com/auth/callback
  ?code=4/0AX4XfWjxxxxxxxxxxxxxBQ
  &state=CSRF_TOKEN

# 3. Your server exchanges the code for tokens:
POST https://oauth2.googleapis.com/token
  grant_type=authorization_code
  &code=4/0AX4XfWjxxx...
  &redirect_uri=https://yourapp.com/auth/callback
  &client_id=YOUR_CLIENT_ID
  &client_secret=YOUR_CLIENT_SECRET
  &code_verifier=ORIGINAL_CODE_VERIFIER   ← PKCE proof

# 4. Google returns three tokens:
{
  "access_token": "ya29.a0...",        ← OAuth: call Google APIs
  "id_token": "eyJhbGciOiJSUzI1...",  ← OIDC: who the user is (JWT)
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "1//0g..."
}

# 5. Your server decodes and VERIFIES the ID token:
import { OAuth2Client } from 'google-auth-library'
const client = new OAuth2Client(CLIENT_ID)
const ticket = await client.verifyIdToken({
  idToken: id_token,
  audience: CLIENT_ID,
})
const payload = ticket.getPayload()
// { sub: "1234567890", email: "[email protected]", name: "Jane Doe", ... }

# 6. Use payload.sub as the stable user identifier in your database.
#    Create the user session. Done.

Note what you never touch: the user's Google password, their full account, or any data beyond what they explicitly approved. The access token only has permissions for the profile and email scopes — nothing more. If the user revokes access from Google's account settings, the tokens become invalid immediately.

OAuth Scopes: The Principle of Least Privilege in Practice

Scopes are space-delimited strings that define what the access token is allowed to do. They are the mechanism that implements the principle of least privilege in OAuth. When your app requests scopes, the authorization server shows them to the user in the consent screen.

Real scope examples from major OAuth providers
# Google APIs
scope=https://www.googleapis.com/auth/gmail.readonly    # read Gmail only
scope=https://www.googleapis.com/auth/calendar          # full calendar access
scope=openid profile email                              # OIDC identity only

# GitHub OAuth Apps
scope=read:user                    # read-only public profile
scope=repo                         # read/write all repositories (!)
scope=repo:status                  # only commit status (least privilege)
scope=admin:repo_hook              # manage webhooks only

# Stripe Connect
scope=read_write                   # full account access
scope=read_only                    # read-only financial data

# Spotify
scope=user-read-email user-read-private          # identity only
scope=playlist-modify-public streaming           # player control + editing

# Best practice: request ONLY the scopes you need.
# Users approve scopes on the consent screen — broad scopes
# reduce conversion and raise security risk.

Scope design is an API design decision. Scopes that are too broad (GitHub's repo gives write access to all repositories) create security risks when tokens are stolen. The GitHub Security Advisory Database documents multiple incidents where compromised tokens with broad scopes led to supply chain attacks on npm packages. The OWASP API Security Top 10 lists Broken Object Level Authorization (BOLA) and Excessive Data Exposure as the top API security risks — both are addressed by granular scopes.

Access Tokens, Refresh Tokens, and ID Tokens: The Three Token Types

OAuth ecosystems use three distinct token types, each with a different purpose and lifetime:

Token TypePurposeTypical LifetimeWhere to StoreSent To
Access TokenCall protected APIs (Authorization: Bearer header)15 min – 1 hourMemory only (SPAs), session (server apps)Resource servers
Refresh TokenGet new access tokens silently when expiredDays – monthsHttpOnly cookie or server-side session. Never localStorage.Authorization server only
ID Token (OIDC)Identify the logged-in user (email, name, sub)1 hour (one-time use)Session after verifying signatureYour app only — never to resource servers

The most common security mistake: storing access tokens or refresh tokens in localStorage. localStorage is accessible to all JavaScript running on the page — a single XSS vulnerability can steal every token stored there. For SPAs, keep access tokens in memory only. Store refresh tokens in HttpOnly, Secure, SameSite=Strict cookies set by a backend-for-frontend (BFF). For a deep dive on the JWT format used by access tokens and ID tokens, see BytePane's JWT tokens explained guide.

OAuth 2.1: The Consolidation of Best Practices

OAuth 2.1 (currently an IETF draft, expected to finalize in 2026) does not introduce new concepts. It consolidates RFC 6749, RFC 7636 (PKCE), RFC 8252 (mobile apps), RFC 9700 (implicit deprecation), and other security BCP documents into a single, opinionated specification that removes the dangerous options.

Per Descope's OAuth 2.1 vs 2.0 analysis (2025), the key changes are:

  • PKCE is mandatory for all authorization code flows — both public and confidential clients.
  • Implicit grant removed — use Authorization Code + PKCE for all browser-based apps.
  • Resource Owner Password Credentials (ROPC) removed — it required direct credential sharing, violating OAuth's premise.
  • Redirect URIs must match exactly — no wildcards, no prefix matching.
  • Refresh tokens must be sender-constrained or one-time-use for public clients.
  • Bearer tokens prohibited in URI query strings — only in Authorization header or request body.

If you follow current best practices today (PKCE for all flows, Authorization Code instead of Implicit, no ROPC), your implementation is already OAuth 2.1-compatible. The changes only remove options that shouldn't have been used anyway. For the complete step-by-step OAuth 2.0 implementation with request/response details, see BytePane's OAuth 2.0 deep-dive guide.

OAuth vs SAML vs OpenID Connect: When to Use Which

ProtocolYear / SpecPurposeToken FormatBest For
OAuth 2.02012 / RFC 6749Authorization (API access delegation)JWT or opaque bearerAPI access, third-party integrations
OpenID Connect2014 / OIDC CoreAuthentication + AuthorizationJWT (ID token + access token)“Login with X,” consumer apps, modern SSO
SAML 2.02005 / OASISAuthentication + AuthorizationXML assertionsEnterprise SSO, ADFS, legacy systems, FedRAMP

For new applications, always choose OIDC over SAML. OIDC is JSON-based, uses standard HTTPS, has broad library support across every language, and is developer-friendly. SAML remains dominant in enterprise environments because of legacy Active Directory integration and compliance frameworks (HIPAA, FedRAMP, FISMA) that specify SAML by name. If you're building B2B SaaS and need to support enterprise SSO, you typically need both: OIDC for your default login flow, SAML for the enterprise accounts that require it.

For API authentication that doesn't involve a human user — API keys, mTLS, JWT bearer — see BytePane's API authentication methods comparison.

Frequently Asked Questions

What is OAuth?

OAuth (Open Authorization) is an open standard that lets applications request limited access to a user's resources on another service without receiving the user's password. Instead of credentials, the user grants permission and the app receives a scoped, time-limited access token. OAuth 2.0 is defined in RFC 6749 (IETF, 2012) and is used by 92% of enterprises in their authentication infrastructure per the 2025 arcade.dev OAuth Adoption Report.

What is the difference between authentication and authorization?

Authentication answers "who are you?" — it verifies identity. Authorization answers "what are you allowed to do?" — it controls resource access. OAuth 2.0 is an authorization framework. It grants an app access to resources but does not verify user identity. OpenID Connect (OIDC) adds the identity layer on top of OAuth 2.0, adding ID tokens with user claims (email, name, sub).

What is the difference between OAuth 1.0 and OAuth 2.0?

OAuth 1.0a used HMAC-SHA1 cryptographic signatures on every HTTP request — secure but complex to implement correctly. OAuth 2.0 simplified the model to bearer tokens over HTTPS: attach the token in the Authorization header. OAuth 2.0 also added multiple grant types (authorization code, client credentials, device) for different client types. The two are incompatible protocols.

What is PKCE in OAuth?

PKCE (Proof Key for Code Exchange, RFC 7636) prevents authorization code interception attacks. The client generates a random code_verifier, hashes it to a code_challenge, and sends the challenge with the auth request. When exchanging the code for tokens, it sends the original verifier — proving it initiated the request. PKCE grew 178% in implementation over two years and is mandatory in the OAuth 2.1 draft.

How does "Sign in with Google" use OAuth?

"Sign in with Google" uses OpenID Connect (OIDC), which is OAuth 2.0 plus an identity layer. Your app redirects the user to Google's authorization server using the Authorization Code + PKCE flow. After consent, your app receives an authorization code, exchanges it for an access token and an ID token (a JWT). The ID token contains the user's identity — sub, email, name. The user's password never leaves Google.

Is OAuth the same as SSO?

OAuth is a building block used to implement SSO (Single Sign-On), but they are not the same. SSO means logging in once and gaining access to multiple applications. OAuth 2.0 + OpenID Connect is the modern protocol stack most often used to implement consumer SSO. SAML 2.0 is used in enterprise environments. OAuth enables the token exchange mechanism that SSO depends on.

What is an OAuth access token?

An access token is a credential representing specific, scoped permissions to access resources on behalf of a user. It is sent in the Authorization: Bearer header with every API request. Access tokens should be short-lived (15 min to 1 hour) to limit damage if stolen. They are typically JWTs containing scope, expiry, and issuer claims. Never store them in localStorage — use memory for SPAs, server sessions for web apps.

What is OAuth 2.1?

OAuth 2.1 is an IETF draft that consolidates OAuth 2.0 and its security best practices into one document. It mandates PKCE for all flows, removes the implicit and Resource Owner Password Credentials grants, requires exact redirect URI matching, and prohibits bearer tokens in URI query strings. It is not a redesign — current best-practice OAuth 2.0 implementations are already compatible.

OAuth 2.0 Technical Deep Dive

Every request and response in the Authorization Code + PKCE flow, security vulnerabilities from OWASP, real code examples for token exchange, and what OAuth 2.1 changes — all in one guide.

Read OAuth 2.0 Technical Guide →