Key Takeaways
- OAuth lets an application obtain limited access to your resources without receiving your password.
- Use Authorization Code with PKCE for user-delegated access; use Client Credentials for suitable machine-to-machine access without a user.
- OAuth authorizes API access. OpenID Connect adds authentication and ID tokens for sign-in.
- Tokens aren't automatically safe: your deployment must protect them, validate them, and enforce their permissions.
OAuth is an authorization framework: it lets MyCoolApp obtain permission to read your Google Calendar without receiving your Google password. OAuth 2.0 works by having an authorization server issue an access token, which the client presents to the API serving the protected data.
What Is OAuth? Authorization, Not Authentication
Authorization answers “What may this application access?” Authentication answers “Who is this user?” The authorization server may authenticate you while handling an OAuth request, but that doesn't make an OAuth access token proof of your identity to the client.
For “Sign in with Google,” Google provides OpenID Connect support. OpenID Connect, or OIDC, builds an identity layer on OAuth 2.0; requesting permission to read Calendar events is a separate authorization concern. Our OpenID Connect example explains the sign-in side.
OAuth Example: Google Calendar and MyCoolApp
Imagine you're building MyCoolApp.com and want to display a user's calendar events. Four roles participate:
- Resource owner: you, the person granting access to your calendar.
- Client: MyCoolApp, the application requesting access.
- Authorization server: Google's authorization service, which handles authorization and issues tokens.
- Resource server: the Google Calendar API, which serves calendar resources after checking authorization.
Google operates both server roles here, but they're distinct responsibilities. An authorization server and resource server can be separate services operated by different organizations.
Scopes and Consent Define the Permission
A scope names a permission the client requests. Google's https://www.googleapis.com/auth/calendar.events.readonly scope allows viewing events on your calendars; it doesn't grant permission to edit them. Choose the narrowest suitable permission from the Calendar scope reference.
The authorization server obtains the necessary approval, commonly through a consent screen. An existing session or previous grant can mean you don't see a fresh login or consent prompt every time. MyCoolApp must handle denied or partially granted permissions rather than assume that requesting a scope guarantees receiving it.
Public Clients Versus Confidential Clients
A public client, such as a browser-based app or an installed native app, can't reliably keep a shared client secret confidential. A secret bundled into downloaded JavaScript or an application binary isn't proof that a request came from your legitimate application.
A confidential client, typically a server-side application, can protect credentials and authenticate itself to the token endpoint. A client ID identifies a registration; it isn't a secret. For native applications, RFC 8252 explains why embedded shared secrets don't provide meaningful client authentication.
How OAuth 2.0 Works: Authorization Code with PKCE
The authorization-code flow separates the browser redirect from the token exchange. In the server-side MyCoolApp example, the browser carries an authorization code back to the client; the access token arrives separately at the client's token exchange.
Browser (you) MyCoolApp client Authorization server Calendar API
|--- Connect -------->|
|<-- redirect --------| scopes + state + PKCE challenge
|---------------- sign in / approve --------->|
|<--------------- code + state ---------------|
|--- callback ------->| validate state
| |--- code + verifier -->| token endpoint
| |<---- access token ----|
| |---------------- Bearer token ------------>|
| |<---------------- events ------------------|- Register the client. Configure its redirect URI with the provider. The authorization server must check it against the registration; native loopback redirects have a defined port-matching exception.
- Create a transaction. Generate an unpredictable, one-time
statevalue and a fresh PKCE verifier. Bind them to the session initiating authorization. - Redirect to the authorization endpoint. Send the client ID, redirect URI, requested scopes,
response_type=code, state, and PKCE challenge. - Obtain authorization. The provider authenticates the user as needed and determines the approved permissions, then redirects the browser back with a code and the original state.
- Validate the callback. Match state to the initiating transaction and reject missing or mismatched values. Handle authorization errors, and apply the provider's issuer-validation requirements before exchanging a code.
- Call the token endpoint over HTTPS. Send the code, original redirect URI, and PKCE verifier. Confidential clients also authenticate using their registered method.
- Receive tokens and call the API. The authorization server checks the code's validity, client binding, redirect URI, and verifier before issuing an access token and, optionally, a refresh token.
Use a maintained OAuth library rather than implementing these checks from scratch. Read the core authorization-code specification alongside current security guidance and your provider's requirements.
PKCE: Bind the Code Exchange to the Original Client
PKCE means Proof Key for Code Exchange. Generate a fresh verifier using a cryptographically secure random generator. RFC 7636 recommends encoding 32 random bytes as base64url without padding, producing a 43-character verifier.
With the S256 method, the challenge is the base64url-encoded SHA-256 hash of the verifier's ASCII bytes, without padding. Send the challenge during authorization and keep the verifier for the token request. The server repeats the transformation and compares it with the challenge associated with the code.
An attacker who intercepts only the authorization code can't redeem it without the verifier. PKCE also protects against authorization-code injection; it doesn't protect an already-stolen bearer token or replace TLS. Current security guidance requires PKCE for public clients and recommends it for confidential clients, too—not just SPAs. Authorization servers must support PKCE.
Illustrative Authorization and Token Requests
These are HTTP fragments, not executable requests. The host, paths, scope, and placeholders describe a fictional provider, not Google's configuration; query and body lines are split for readability.
# Illustrative authorization request, sent through the browser over HTTPS.
GET /authorize?response_type=code
&client_id=MYCOOLAPP_CLIENT_ID
&redirect_uri=https%3A%2F%2Fmycoolapp.example%2Foauth%2Fcallback
&scope=calendar.read
&state=<RANDOM_STATE>
&code_challenge=<CHALLENGE_DERIVED_FROM_VERIFIER>
&code_challenge_method=S256 HTTP/1.1
Host: auth.exampleAfter validating the callback, a public client exchanges the code as follows. A confidential client additionally supplies the provider-required client authentication; PKCE doesn't replace that authentication.
# Illustrative public-client token request, sent over HTTPS.
POST /token HTTP/1.1
Host: auth.example
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&client_id=MYCOOLAPP_CLIENT_ID
&code=<CODE_FROM_CALLBACK>
&redirect_uri=https%3A%2F%2Fmycoolapp.example%2Foauth%2Fcallback
&code_verifier=<ORIGINAL_VERIFIER>OAuth 2.0 Grant Types: Which Should You Use?
A grant is the credential or authorization basis used to obtain an access token. Pick the flow according to whether a user delegates access, whether the client can protect credentials, and what the authorization server supports.
| Grant | Appropriate use or migration guidance | Exchange |
|---|---|---|
| Authorization Code with PKCE | Use for user-delegated access from web, browser-based, and native applications. | Browser authorization produces a code; the client exchanges the code and verifier for tokens. |
| Client Credentials | Use for a confidential client's own authorized access without a user. | The client authenticates directly to the token endpoint with grant_type=client_credentials. |
| Implicit | Avoid for new implementations; prefer Authorization Code with PKCE. | Returns an access token in the authorization response, increasing token exposure and replay risks. |
| Resource Owner Password Credentials | Do not use; migrate to an interactive authorization flow. | The client collects the user's password and exchanges it for a token. |
Client Credentials isn't a shortcut to a user's Calendar permissions: no user authorizes access during that exchange. Provider-specific service identities and delegation require their own configuration.
RFC 9700, the OAuth security best current practice, says the password grant must not be used and recommends against the implicit grant. Password collection expands credential exposure and doesn't fit many multi-step authentication methods.
Access Tokens, Refresh Tokens, and ID Tokens
| Token | Purpose | Intended recipient |
|---|---|---|
| Access token | Authorizes access to protected resources within granted permissions. | The resource server. |
| Refresh token | Obtains new access tokens without repeating the original user authorization each time. | The authorization server's token endpoint, not the resource API. |
| ID token | Conveys claims about an authentication event and the user; belongs to OIDC, not core OAuth. | The client application. |
Access tokens need not be JSON Web Tokens (JWTs); they can be opaque strings. Don't build client-side identity logic by decoding an access token. OIDC clients validate ID tokens according to the protocol, including issuer, audience, expiration, and nonce when used.
Many deployments use short-lived access tokens and may issue refresh tokens, but OAuth doesn't prescribe a universal token lifetime. Issuance and lifetime are provider policies. A revocation mechanism also needs implementation support; don't assume every token becomes unusable everywhere immediately after revocation.
How Does OAuth Work in a REST API?
A bearer token grants access to whoever possesses it, subject to its validity and permissions. Send it over TLS using the Authorization header. With a Google-issued token carrying suitable Calendar permission, a request to list primary-calendar events looks like this:
# Illustrative API request, sent over HTTPS.
GET /calendar/v3/calendars/primary/events HTTP/1.1
Host: www.googleapis.com
Authorization: Bearer <GOOGLE_ACCESS_TOKEN>If you're building the resource server, receiving a token isn't enough:
- Validate it using the provider's supported mechanism. For JWT access tokens, verify the signature and allowed algorithm, trusted issuer, intended audience, and expiration. Merely decoding JSON isn't validation.
- For opaque tokens, use an authorized introspection endpoint or the issuer's supported validation mechanism. Introspection reports whether a token is active and may return authorization metadata.
- Enforce authorization. Check scopes and application-specific resource permissions for the requested operation, not just whether the token is valid.
The JWT access-token profile details validation rules. Under the bearer-token specification, invalid or expired tokens should receive HTTP 401; insufficient scope should receive HTTP 403.
OAuth isn't specific to REST and doesn't define your API's resource model. Whether you choose REST or SOAP, token validation and permission enforcement remain implementation responsibilities.
OAuth 1.0 vs OAuth 2.0 Security
OAuth 2.0 is a distinct framework, not a backward-compatible revision of OAuth 1.0. Its extensible grant model accommodates different authorization scenarios; describing OAuth 1.0 as having “one flow” misses the important differences.
- OAuth 1.0: provides request-signing mechanisms. Signing can authenticate requests and protect covered request components against modification, but it doesn't encrypt traffic.
- OAuth 2.0: commonly uses bearer access tokens over TLS rather than OAuth 1.0-style request signatures. Bearer-token theft can therefore enable replay.
- Neither version guarantees a token lifetime: don't equate OAuth 1.0 with permanent tokens or OAuth 2.0 with automatically short-lived, immediately revocable tokens.
The OAuth 1.0 specification explicitly separates request integrity from confidentiality. Use TLS with either protocol in deployment; our explanation of how TLS works covers the transport protection. PKCE protects the code exchange, not every later API request.
A Current Example: OAuth for MCP Tool Access
Remote tools used by AI agents can use the same authorization model. In the Model Context Protocol's HTTP authorization specification, the MCP client is the OAuth client and the protected MCP server is the resource server. This authorization mechanism builds on OAuth 2.1; authorization isn't mandatory for every MCP deployment.
As of October 17, 2026, OAuth 2.1 remains an IETF Internet-Draft. For protected MCP access, request a token for the intended MCP server; don't pass a Calendar access token to an unrelated tool server as though it were interchangeable.
Production Checklist
- Use a maintained library and configure trusted provider endpoints and registered redirect URIs explicitly.
- Bind state and the verifier to the initiating transaction; test missing state, denied consent, reused codes, and incorrect verifiers.
- Keep tokens out of URLs and logs, protect stored refresh tokens, and send tokens only to their intended recipients.
- For public clients receiving refresh tokens, use rotation or sender-constrained refresh tokens as required by current security guidance. Rotation replaces the refresh token when it is used.
- Test API rejection of wrong-audience tokens, expired tokens, and insufficient permissions—not just the successful login path.
The design goal is limited, enforceable access without sharing the user's password—not merely obtaining a token.
FAQ
What is OAuth 2.0 and how does it work?
OAuth 2.0 lets a client obtain limited access to protected resources without receiving the resource owner's password. In the authorization-code flow, the client exchanges an authorization code for an access token, then presents that token to the resource server.
What is the difference between OAuth and OpenID Connect?
OAuth governs authorized access to resources. OpenID Connect adds authentication and ID tokens so a client can verify information about a user's sign-in; an OAuth access token isn't a substitute for an ID token.
When should I use Authorization Code with PKCE?
Use it for user-delegated access from browser-based, native, and server-side applications. Current OAuth security guidance requires PKCE for public clients and recommends it for confidential clients.
Are the OAuth implicit and password grants still recommended?
No. RFC 9700 prohibits the Resource Owner Password Credentials grant and recommends against the implicit grant; use Authorization Code with PKCE for new user-delegated integrations.
Does OAuth require HTTPS?
Use HTTPS for authorization endpoints, token exchanges, and bearer-token API requests. Native-app loopback redirects have a narrow HTTP exception; PKCE doesn't replace TLS.
Further Reading
- RFC 6749: OAuth 2.0 Authorization Framework — roles, grants, and token exchanges.
- RFC 9700: OAuth Security Best Current Practice — PKCE, unsafe grants, redirects, and token protection.
- RFC 7636: Proof Key for Code Exchange — verifier generation and challenge validation.
- RFC 6750: Bearer Token Usage — API authorization headers and error responses.
- OpenID Connect Core — authentication, ID tokens, and validation.
- Google's server-side OAuth guide — provider-specific registration, consent, and token handling.
- Google Calendar authorization scopes — available Calendar permissions.
- MCP HTTP authorization specification — applying OAuth to protected remote tools.
