What is OAuth?
OAuth is an authorization framework for granting a client limited access to a protected service. For example, a SaaS reporting app might obtain permission to read a user's export metadata from another service without asking for that service's password.
RFC 6749 defines the framework's roles and grants. Current implementations also need later security guidance, including RFC 9700. A diagram of an older flow is not sufficient evidence that the flow is a suitable default today.
This guide follows an original fictional connection between QueueNote and an export service. Domains, client identifiers, scopes, and request descriptions are teaching examples. They are not real endpoints, working credentials, or a production integration.
Download the walkthrough and local PKCE lab
The text walkthrough contains the fictional actors, request fields, success and denial paths, a token-handling review, and a blank integration checklist. The JavaScript lab demonstrates only the S256 PKCE calculation and proof comparison.
Run node oauth-pkce-lab.mjs with Node.js 22 or later. It generates a random local verifier, prints the public challenge, and shows that the original verifier matches while a different verifier does not. It sends no requests, writes no files, and obtains no token or authorization grant.
The lab deliberately does not implement an authorization server, callback session, consent interface, or production token store. Use it to understand one mechanism, then rely on a maintained integration and the actual provider contract for a real connection.
Identify the actors and the permission being requested
The resource owner is the person or entity able to authorize access. The client is the app requesting it. The authorization server handles the authorization process and token issuance, while the resource server exposes the protected API.
In the exercise, QueueNote is the client and a separate export service holds the protected metadata. A browser carries the user's interaction with the authorization service and the redirect back to QueueNote. The client later calls the API within the granted scope.
The illustrative scope is exports:read. Its spelling and meaning are invented; real scopes are defined by the provider. Asking for a scope does not establish that it was granted, and a token for one audience or account should not be treated as permission for every API or workspace.
Follow the authorization-code example
QueueNote starts a connection transaction and sends the browser to the authorization service with the client identifier, registered redirect URI, requested scope, response type, and transaction protections. The user can approve or deny the request at that service.
On approval, the browser returns to the client's registered callback carrying an authorization code and the relevant transaction response. The client must associate the response with the correct connection attempt and user context before continuing. A denied or invalid response should not leave a connected state.
The client exchanges the code at the token endpoint using the required redirect information, PKCE verifier, and any client authentication required for its client type. The authorization service validates the grant before returning tokens. The code is not the access token.
The walkthrough uses placeholders and reserved example domains so it cannot accidentally authorize a real connection. It records the desired local workspace separately from the remote resource identity; the application must validate their relationship rather than trusting a submitted workspace ID.
Understand what PKCE adds
PKCE binds the authorization-code exchange to a verifier created for that transaction. With S256, the public challenge is the base64url-encoded SHA-256 digest of the verifier. The authorization request carries the challenge; the later token request carries the verifier.
RFC 7636 specifies the verifier format and transformation. The local lab accepts the specified 43–128-character unreserved ASCII format and generates 32 random bytes encoded as a 43-character base64url verifier. Its example uses S256.
RFC 9700 requires PKCE for public clients and recommends it for confidential clients. It also addresses transaction binding and downgrade protection. A fixed verifier reused across connections defeats the purpose of a fresh transaction secret.
PKCE is one protection, not the entire implementation. The client still needs the appropriate redirect validation, transaction/session binding, grant checks, secure transport, and token handling. Do not interpret a matching hash in the local exercise as successful authentication or a completed authorization.
Distinguish OAuth authorization from sign-in
OAuth access answers whether a client can perform a permitted operation. It does not, by itself, define the application's complete sign-in protocol. OpenID Connect adds an identity layer on top of OAuth 2.0 and defines authentication-related behavior.
An access token and an ID token serve different purposes. Do not use a token as proof for an unrelated audience or invent an identity rule from whichever field looks like an email address. A maintained OpenID Connect integration should perform the validations required by the actual protocol and provider.
For an application using Better Auth or Clerk, distinguish the provider's session and organization model from a separate delegated API connection. A signed-in user still needs the appropriate authorization for the target workspace and operation.
Plan failure handling and token ownership
Walk through denial, an expired or replayed code, a mismatched transaction, an invalid verifier, reduced scope, and a revoked connection. The interface should show the actual state rather than marking a connection complete before the required exchange and identity checks finish.
Keep token storage and refresh ownership explicit. Secrets must not be placed in a public client bundle, logs, or a shared troubleshooting file. Choose a storage and transport design appropriate to the application's architecture and provider integration.
Disconnecting a local record and revoking a remote grant are related but different actions. Document the provider's supported behavior and what happens to queued work. The API integration guide helps connect those decisions to error handling and recovery.
What the local lab verifies
The lab checks verifier format, derives the S256 challenge, and compares it with an expected challenge. Its tests include a published RFC calculation vector, fresh random pairs, a different valid verifier, invalid lengths and characters, and malformed challenge inputs.
Those checks establish local calculation behavior. They do not test a browser session, a provider callback, token issuance, refresh, revocation, consent, or a live resource API. No real user authorization was requested for this article.
Primary sources and original materials checked October 28, 2026. Verify the current provider documentation and security requirements when implementing a real connection.