AlgoMaster Logo

OAuth 2.0

High Priority15 min readUpdated September 13, 2026
Listen to this chapter
Unlock Audio

Suppose you are building a reading app called ReadShelf and want customers to import their private reading lists from a bookstore. Asking for a customer's bookstore password would give ReadShelf a credential with far more authority than this feature needs. The customer also needs a way to disconnect ReadShelf without changing that password.

OAuth 2.0 provides a framework for granting an application limited access to an HTTP service.

This chapter explains the participants, the authorization code flow with PKCE, the requests involved, and the checks that keep a grant tied to the intended application and transaction.

The example uses a ReadShelf web application with a backend that stores credentials and calls the bookstore API. All communication uses HTTPS. The bookstore runs an authorization service at auth.bookstore.example and a resource API at api.bookstore.example. Endpoint paths, scope names, and token lifetimes are choices this fictional service makes.

1. Delegated Access

With OAuth, the customer interacts with the bookstore to authorize ReadShelf. ReadShelf receives an access token, a credential the bookstore API accepts for the permitted access. The customer's bookstore password stays with the bookstore.

The authorization can be narrow. ReadShelf asks to read reading lists, and the bookstore issues access that permits only that purpose. A token for reading lists should not permit purchasing books, changing account settings, or reading another customer's private data.

Four roles describe the participants:

Scroll
OAuth roleResponsibilityExample
Resource ownerCan authorize access to protected resourcesThe bookstore customer
ClientRequests and uses accessReadShelf
Authorization serverProcesses authorization and issues tokensBookstore authorization service
Resource serverAccepts tokens and serves protected resourcesBookstore API

The authorization server and resource server are separate roles even when the same organization operates both. The browser transports some messages between participants; in this example, ReadShelf's backend is the OAuth client that exchanges a code and uses the access token.

The diagram shows who grants, issues, and uses access:

OAuth standardizes obtaining and using delegated access. It does not prescribe the bookstore's ownership rules or a universal token format. An access token can be an opaque value whose meaning the API resolves through trusted server-side information.

OAuth also does not, by itself, define a login identity assertion for ReadShelf. The customer may authenticate at the bookstore as part of authorization, but ReadShelf must not treat possession of an arbitrary access token as proof of who signed in to ReadShelf. OpenID Connect adds a standardized identity layer when that is the intended feature.

2. Client Registration

Before sending customers to the bookstore, ReadShelf registers its application. Registration establishes a client ID, allowed redirect URIs, and the client's authentication method where applicable.

A client ID identifies a registration. It is public and cannot authenticate the application by itself. The redirect URI is the client endpoint that receives the authorization response, such as https://readshelf.example/oauth/callback.

The ability to protect credentials determines the OAuth client type:

Scroll
Client typeCredential boundaryExample
ConfidentialCan protect credentials it uses to authenticate at the token endpointReadShelf's controlled backend
PublicCannot reliably keep a distributed credential secretA browser-only app or installed mobile app

Putting a client secret in a JavaScript bundle does not make a browser-only application confidential. Users can inspect the bundle. Public clients use a flow that accounts for that limitation, without pretending that a shared embedded secret proves application identity.

ReadShelf's backend is confidential. This example registers HTTP Basic client authentication at the token endpoint, and stores its client secret on the backend. Production deployments may support other registered authentication methods; use the method the client and authorization server agreed to use.

Register complete callback URLs. For this web application, the authorization server must match the supplied redirect URI exactly against a registered value. Wildcard hosts, partial path checks, and callbacks that forward to arbitrary destinations can send authorization responses to an attacker.

The client also needs trusted authorization and token endpoint configuration. Do not let a callback parameter choose a new token endpoint and cause ReadShelf to send a code or client credential there.

3. Authorization Code Flow with PKCE

An authorization grant is the authorization the client uses to obtain an access token. In the authorization code flow, the browser delivers a short-lived authorization code to ReadShelf's callback. ReadShelf exchanges that code at the token endpoint. The code is single-use. The resource API does not accept it as an access token.

PKCE (say “pixy”) stands for Proof Key for Code Exchange. It binds that exchange to a secret the client generates for the authorization attempt. The client creates a random code verifier and sends a derived code challenge in the authorization request. It later supplies the verifier when redeeming the code.

Use the S256 challenge method: hash the verifier's ASCII bytes with SHA-256, then encode the result with URL-safe Base64 without padding. An interceptor who learns the authorization code and challenge still lacks the verifier it needs to redeem the code.

Current OAuth security guidance requires PKCE for public clients and recommends it for confidential clients. ReadShelf uses it alongside client authentication. PKCE binds the authorization transaction; the client secret authenticates the registered backend. They serve different purposes.

ReadShelf also creates an unpredictable, one-time state value and binds it to the initiating browser session. On callback, it requires an exact match with the outstanding transaction. This helps prevent cross-site request forgery, where an attacker causes a browser to complete an unintended authorization transaction. Store the verifier, state, expected authorization server, and callback URI together with a short expiry, and consume the transaction once.

The complete flow includes a browser-facing authorization exchange and a direct backend token exchange:

Connect bookstore accountRedirect with state and PKCE challengeAuthorization requestAuthenticate and request approval as neededApprove reading-list accessRedirect with code and stateCallback with code and stateValidate pending transactionCode, verifier, and client authenticationAccess tokenRead lists with access tokenAuthorized reading listsCustomer browserReadShelf backendBookstore authorization serverBookstore APICustomer browserReadShelf backendBookstore authorization serverBookstore API
12 / 12
algomaster.io

The access token reaches ReadShelf through the token response. In this backend design, it remains on the server. ReadShelf's browser session has its own session protection and does not need to receive the bookstore token.

4. Authorization Request and Callback

When the customer selects “Connect bookstore,” ReadShelf creates the transaction and redirects the browser to the authorization endpoint. The browser then makes this request:

response_type=code selects an authorization-code response. The scope parameter requests a named area of access, here reading-lists:read. Scope names belong to the bookstore's contract, and the client must not assume the authorization server will always grant the requested access.

All credentials, state values, and codes these examples show are public examples. The verifier and challenge the examples use below form a matching demonstration pair, but a real client generates a fresh cryptographically random verifier and state for each attempt. A verifier must contain 43 to 128 permitted unreserved characters.

The bookstore validates the request and authenticates the customer as necessary. It can reuse an existing authenticated session. It asks for approval when its consent policy requires it; OAuth does not require a fresh consent screen on every attempt.

After approval, the authorization server returns a redirect through the customer's browser:

The browser follows that redirect to ReadShelf. The callback handler checks the session-bound state and pending transaction before attempting the exchange. It rejects unknown, expired, or already consumed transactions.

The callback should avoid third-party scripts and resource loads that could expose its query parameters. Redact authorization codes from logs and redirect to a clean application URL after processing. A short lifetime and single-use redemption reduce exposure but do not make a code safe to publish.

5. Token Exchange and API Access

ReadShelf sends the code directly from its backend to the token endpoint. The request is form-encoded, and it includes the same redirect URI it used in the authorization request:

The Basic value encodes the demonstration client ID readshelf_web and placeholder secret EXAMPLE_CLIENT_SECRET. Encoding does not conceal a secret, so the request requires HTTPS. This client credential stays out of browser requests. A public client would use its registered public-client exchange, including its client ID without a shared client secret.

The authorization server verifies client authentication and checks that the code is valid and unused, that it issued the code to this client, and that the code matches the supplied redirect URI. It derives the challenge from the submitted verifier and compares it with the challenge it recorded for the code. These bindings prevent a code the server intended for one transaction from becoming a general-purpose credential.

A successful response is:

The access token expires after 900 seconds in this example. The token response carries cache-prevention headers. A refresh token, which can obtain replacement access tokens at the authorization server, is optional; this example does not issue one. ReadShelf must not assume that every successful exchange permits unattended access indefinitely.

ReadShelf stores the token under the correct local user's bookstore connection, then uses it to retrieve that connection's lists:

All HTTP examples use exact single-line bodies without trailing newlines. The bookstore chooses no-store for private API responses.

The API validates the token through its configured trust relationship with the authorization server. It checks that the token is usable for this API and that the grant permits reading lists. It then applies customer and resource policies before constructing the collection. A reading-lists:read grant never means “return every customer's lists.”

ReadShelf should treat the token as opaque unless the provider explicitly defines client-side processing. The API's verification mechanism and the token's internal representation are separate design choices from the authorization code flow.

6. Errors and Interrupted Flows

OAuth failures occur at different endpoints, and their response formats belong to those protocols. A token-endpoint error uses OAuth's JSON error fields; the server should not replace it with an unrelated application error envelope.

Authorization Refusal

If the customer declines access after the authorization server has validated the client and redirect URI, the server can return:

This is an alternative outcome to the successful callback for that transaction. ReadShelf validates state on error callbacks too, shows that ReadShelf did not finish connecting to the bookstore, and lets the customer continue using unrelated features.

If the redirect URI is invalid, the authorization server must not redirect the error to that untrusted URI. It reports the problem locally. Otherwise, even error handling could become a mechanism for sending users or authorization data to an attacker.

Invalid Code Exchange

An expired or already redeemed code, a code the server assigned to another client, or a failed verifier check can produce this token response:

Correct client authentication does not make a bad grant usable. Conversely, failed client authentication is an invalid_client error. If the client attempted HTTP Basic authentication, the token endpoint responds with 401 and a matching Basic challenge.

A missing required token-request parameter can produce 400 with invalid_request. These are protocol validation failures, so this endpoint does not apply the bookstore resource API's 422 convention for invalid business fields.

A timeout during code exchange creates uncertainty: the authorization server may have consumed the code even if ReadShelf never received the token response. Do not promise that retrying a code is idempotent. Handle an ambiguous or failed exchange through the provider-supported recovery behavior, and restart authorization when ReadShelf cannot recover the transaction.

Resource API Refusal

A token can be valid but insufficient for the requested API operation. If ReadShelf attempts to modify a list using its read-only token, the API can return:

An expired or otherwise invalid bearer token instead leads to 401 with a Bearer challenge and invalid_token. Repeating the same request cannot add permission to a token. ReadShelf should request broader access only when a feature needs it and the customer chooses to authorize it.

Also define what happens to existing tokens and grants when a user disconnects an account. Deleting ReadShelf's local token stops its own use, but does not necessarily revoke copies or all tokens the grant authorizes. Use the authorization service's supported revocation or grant-removal mechanism, and account for its actual enforcement delay. Closing a browser session is not a guarantee that delegated API access has ended.

7. Other Grants and Flow Selection

A backend inventory job may need access as its own registered application, without a customer approval interaction. The client credentials grant allows a confidential client to authenticate at the token endpoint and request access the authorization server permits for that client.

The flow is shorter because there is no browser callback or customer authorization code:

The token represents the client's authorized access. Adding a customer ID to a request does not convert that grant into customer consent. Public clients cannot use client credentials as a way to obtain trusted application identity from an embedded secret.

For customer-delegated access, use authorization code with PKCE. Avoid choosing an older flow merely because an example requires fewer requests. Current security guidance discourages the implicit grant, which returns access tokens through the authorization response, and prohibits the resource owner password credentials grant, which asks the client to collect the user's password.

Use a maintained OAuth implementation and configure the actual client type and provider contract. Registration, callback validation, transaction storage, token exchange, and API enforcement must agree. A working redirect alone is only one part of a completed authorization flow.

Summary

OAuth 2.0 lets applications obtain limited API access through an authorization server. Keep the resource owner, client, authorization server, and resource server distinct, and choose the grant according to whose access the application needs.

For delegated access, authorization code with PKCE ties a one-time code to the initiating transaction. Validate redirects and callback state, authenticate confidential clients, protect tokens, and enforce the grant's limits at the API. Handle authorization, token, and resource errors according to the endpoint where they occur.