- App requests permission from the authorization server
- Authorization server issues an access token
- Resource API checks the token and allowed operation
Start with the request your application wants to make. Reading a profile, listing repositories, and creating a calendar event are different operations. Each needs permission from the service holding that resource. A button labeled “Continue with Google” hides that distinction; the HTTP requests underneath don’t.
The useful debugging question is therefore more specific than “Did OAuth work?” Ask which application received which credential, and which server is supposed to accept it. That question also gives you something concrete to check when reviewing auth code produced by a coding assistant.
Four roles, even when one provider runs two of them
OAuth names four roles in RFC 6749 §1.1. The names describe responsibilities, not necessarily separate deployments.
| Role | Concrete responsibility |
|---|---|
| Resource owner | The person or entity able to grant access to the resource |
| Client | Your application, requesting and using that access |
| Authorization server | The service that evaluates authorization and issues tokens |
| Resource server | The API that checks tokens before serving protected data |
The browser carries the user through a redirect-based flow. It isn’t automatically the OAuth client: for a server-rendered web app, the client can be your backend. The provider may operate both the authorization server and resource API, but token issuance and API enforcement remain distinct jobs.
In a delegated user flow, the person authenticates at the provider. Your app doesn’t need their provider password. The provider can also apply its own authentication policy without teaching your app how to implement that policy.
Not every OAuth grant involves a person clicking a consent screen. Client credentials can authorize an application acting on its own behalf. Conversely, an existing provider session or previously granted permission may make a user flow appear almost immediate. The absence of a new password prompt doesn’t mean the authorization checks disappeared.
An access token is permission for a particular recipient
An access token authorizes resource requests; it isn’t a universal credential for every service that recognizes the user. Its meaning depends on the issuing server, the intended resource server, the granted permissions, and its lifetime.
Scopes are names for permissions defined by the service. There is no universal rule that a scope called read means the same thing across providers. Request the operations you actually need, then check the permissions that were granted. RFC 9700 §2.3 recommends restricting token privileges and intended recipients.
OAuth doesn’t require access tokens to be JWTs. A token may be an opaque string whose details only the server can resolve. Even when it has a readable payload, decoding it doesn’t establish that it is valid or that your API should accept it. The receiving server needs the validation rules for that token type and issuer.
A refresh token, when offered, goes to the authorization server to obtain replacement access tokens. It doesn’t go to the resource API. Refresh is optional, so code that assumes every OAuth response contains a refresh token is already guessing beyond the base contract.
The redirect returns a code, not a finished app session
The modern default for a redirect-based integration is the authorization code flow with PKCE. The browser returns a short-lived code. The client redeems it at the token endpoint, where the server checks its transaction bindings before issuing tokens.
This split keeps an access token out of the callback URL. PKCE adds a transaction-specific verifier: the authorization request carries a derived challenge, and redemption must present the corresponding verifier. A confidential backend also authenticates as the registered client. Those checks protect different boundaries.
Avoid copying an old tutorial simply because its redirect succeeds. RFC 9700 updates the original OAuth security advice, discourages implicit access-token delivery, and prohibits the resource-owner password grant. A working redirect alone tells you very little about the rest of the implementation.
Identity evidence and local permissions come next
OAuth alone doesn’t standardize the evidence your app needs to identify the signed-in person. OpenID Connect adds that identity layer, including an ID token intended for the client. Some providers instead document an OAuth-backed profile API that a login integration can use.
- Provider establishes an account identity through OIDC or its documented profile API.
- App backend maps the trusted subject to a local user record.
- App creates its own session and checks local permissions on later requests.
An authenticated user isn’t automatically an administrator, a paying customer, or a member of an organization. Those are application facts. A provider profile doesn’t authorize a database query against another user’s records.
The app session has its own expiration and revocation rules too. Logging out of your app need not log the person out of the provider. Expiring a provider access token need not expire an already-created local session. Design that relationship deliberately rather than letting a variable named token decide it.
Where AnyOAuth fits
AnyOAuth, which we build, uses Google’s OIDC identity validation and GitHub’s OAuth-authorized profile lookup to establish who signed in. The provider tokens used during sign-in remain inside AnyOAuth’s API; they aren’t persisted or handed to customer apps.
Your backend retrieves the normalized identity using an AnyOAuth profile token, then creates its own application session. That handoff answers a login question. It doesn’t grant your app permission to list repositories or read a calendar.
For delegated provider API access, use an integration that requests and manages the relevant permissions. The integration documentation and security model describe AnyOAuth’s narrower boundary; the OAuth versus SAML comparison explains the separate federation question.
Keep identity keys scoped to their source. AnyOAuth identities are project/provider/subject-scoped, and equal emails don’t merge accounts. Email is useful profile data, but treating it as a global identity silently changes the trust model.
Sources
Primary protocol references retrieved 2026-10-06:
- IETF, RFC 6749: The OAuth 2.0 Authorization Framework, especially §§1.1–1.5 and 4.1.
- IETF, RFC 7636: Proof Key for Code Exchange, especially §4.
- IETF, RFC 9700: Best Current Practice for OAuth 2.0 Security, especially §§2.1–2.4.
- OpenID Foundation, OpenID Connect Core 1.0, especially §§1–2.