OAuth 2.0 delegates authority to call a resource server. OpenID Connect adds identity assertions for a client. Confusing the two causes APIs to accept ID tokens, clients to infer identity from access tokens, and browser applications to leak bearer credentials. This protocol deep dive follows Authorization Code with PKCE and then attacks every trust boundary.
The core idea
OAuth delegates limited authority to access a protected resource; OpenID Connect lets a client verify an authentication event. Tokens therefore have different recipients and meanings. Secure implementation starts by naming actors and audiences, then protects every redirect, code exchange, session, policy decision, and key lifecycle.
four OAuth actors, one OIDC client
Resource owner, client, authorization server, and resource server have different responsibilities. This distinction matters because a production contract is defined by observable behavior, not by the framework or storage engine used today. draw front-channel and back-channel hops before choosing a flow Write the guarantee down in terms a caller and an operator can independently verify.
sequenceDiagram
User->>Client: Sign in
Client->>AS: authorize + challenge
AS-->>Client: code
Client->>AS: code + verifier
AS-->>Client: access token + ID token
Client->>API: access tokenOnly the access token crosses to the API.
The example is useful because it exposes identity, state, and the boundary of responsibility. It should be reviewed alongside threat models for interception and compromised clients. If a public native or browser client pretends an embedded secret is confidential, the design has hidden an important precondition. Track flow use and rejected requests by client type so violations appear as evidence rather than customer anecdotes.
On the wire: PKCE binds the authorization code
The verifier proves the redeemer initiated the request. Protocol participants cannot rely on shared memory or good intentions, so generate high entropy, send its S256 challenge, and redeem once
code_challenge = BASE64URL(SHA256(code_verifier))
authorize: code_challenge + method=S256
token: code + original code_verifierAn interceptor holding only the code cannot redeem it.
Every field or status in that exchange needs one owner and one interpretation. Unknown, duplicated, expired, and reordered input must have defined handling. Specifically test intercepted, expired, duplicate, and wrong-verifier codes. A subtle interoperability failure occurs when the verifier is predictable, reused, or written to logs. Useful telemetry includes token errors and challenge methods, tagged by peer, route, and deployed contract version without exposing credentials.
Security boundary: redirect, state, and nonce
Authorization responses travel through attacker-influenced browsers. Assume input and redirects can be controlled by an attacker. register exact redirects, bind state to the browser transaction, and validate OIDC nonce
Store one-time state, nonce, return path, and verifier server-side. Consume them on callback. Validate any return path against a local allowlist rather than accepting an arbitrary URL.
Use maintained cryptographic libraries and keep secrets out of examples, traces, and error responses. Add negative cases for modified state, replayed callback, wrong nonce, and encoded redirects. The control is bypassable if wildcards or open redirectors send codes to an attacker. Monitor callback rejection reason without codes or tokens by safe reason categories, rate-limit abusive paths, and retain enough context for investigation without retaining sensitive payloads.
Comparison: access token versus ID token
Signature validity does not make one token interchangeable with another. A comparison is only useful when the criteria match the workload, so validate each token only at its intended recipient
| Property | Access token | ID token |
|---|---|---|
| Audience | Resource server | Client ID |
| Purpose | API authorization | Authentication result |
| Sent to API | Yes | No |
| Required format | Often opaque/JWT | JWT |
| Key claims | issuer, audience, expiry | plus subject, nonce rules |
Treat each row as a hypothesis, not a universal verdict. Weight correctness guarantees before convenience when a mistake is expensive. Prototype wrong issuer, audience, algorithm, expiry, and token type. Beware the conclusion when an API accepts a signed ID token as authority; benchmark data without representative distribution and contention is especially misleading. Revisit the choice using validation failures by safe category.
Security boundary: scope is not object authorization
A scope grants a capability class, not ownership of every object. Assume input and redirects can be controlled by an attacker. enforce tenant, role, ownership, and resource state inside the API
token scope: orders:write
policy:
principal.tenant == order.tenant
principal can cancel
order.state in [pending, confirmed]All predicates are required; scope alone is insufficient.
Use maintained cryptographic libraries and keep secrets out of examples, traces, and error responses. Add negative cases for a matrix of scope, role, tenant, owner, and state. The control is bypassable if cross-tenant identifiers pass because the scope matches. Monitor denials by policy and unusual probing by safe reason categories, rate-limit abusive paths, and retain enough context for investigation without retaining sensitive payloads.
Operating reality: sessions, refresh, and signing keys
Browser-readable long-lived bearer tokens magnify XSS, while key rotation and revocation remain lifecycle problems. The mechanism is not production-ready until the team can prefer a backend session, secure cookies, bounded JWKS refresh, and refresh-token reuse detection
A backend-for-frontend stores provider tokens server-side and gives the browser an HttpOnly, Secure, SameSite cookie with CSRF protection. On unknown kid, it refreshes trusted JWKS once with rate limiting.
Alerts should indicate customer impact and a plausible action; lower-severity diagnostics can remain on dashboards. Exercise key rollover, issuer outage, concurrent refresh, CSRF, logout, and revoked users during a game day. Operations will stall if token material enters logs or attacker-chosen key URLs are fetched. Measure unknown keys, refresh reuse, session anomalies, and sensitive-log scans with rates, percentiles, age, and saturation as appropriate, and link every alert to an owned recovery procedure.
Adversarial conformance lab
1. Rehearse four oauth actors, one oidc client
Before sign-off, restate this article-specific claim in one sentence: Resource owner, client, authorization server, and resource server have different responsibilities. Build a controlled exercise that includes threat models for interception and compromised clients. Record the expected durable state, response, and operator action before running it. During the exercise, deliberately introduce the condition where a public native or browser client pretends an embedded secret is confidential. The team must explain whether to retry, reject, compensate, roll back, or wait. Preserve flow use and rejected requests by client type with enough dimensions to compare the expected and observed path. Finish by assigning ownership and documenting the threshold that would force the design to be reconsidered.
2. Rehearse pkce binds the authorization code
Before sign-off, restate this article-specific claim in one sentence: The verifier proves the redeemer initiated the request. Build a controlled exercise that includes intercepted, expired, duplicate, and wrong-verifier codes. Record the expected durable state, response, and operator action before running it. During the exercise, deliberately introduce the condition where the verifier is predictable, reused, or written to logs. The team must explain whether to retry, reject, compensate, roll back, or wait. Preserve token errors and challenge methods with enough dimensions to compare the expected and observed path. Finish by assigning ownership and documenting the threshold that would force the design to be reconsidered.
3. Rehearse redirect, state, and nonce
Before sign-off, restate this article-specific claim in one sentence: Authorization responses travel through attacker-influenced browsers. Build a controlled exercise that includes modified state, replayed callback, wrong nonce, and encoded redirects. Record the expected durable state, response, and operator action before running it. During the exercise, deliberately introduce the condition where wildcards or open redirectors send codes to an attacker. The team must explain whether to retry, reject, compensate, roll back, or wait. Preserve callback rejection reason without codes or tokens with enough dimensions to compare the expected and observed path. Finish by assigning ownership and documenting the threshold that would force the design to be reconsidered.
4. Rehearse access token versus id token
Before sign-off, restate this article-specific claim in one sentence: Signature validity does not make one token interchangeable with another. Build a controlled exercise that includes wrong issuer, audience, algorithm, expiry, and token type. Record the expected durable state, response, and operator action before running it. During the exercise, deliberately introduce the condition where an API accepts a signed ID token as authority. The team must explain whether to retry, reject, compensate, roll back, or wait. Preserve validation failures by safe category with enough dimensions to compare the expected and observed path. Finish by assigning ownership and documenting the threshold that would force the design to be reconsidered.
5. Rehearse scope is not object authorization
Before sign-off, restate this article-specific claim in one sentence: A scope grants a capability class, not ownership of every object. Build a controlled exercise that includes a matrix of scope, role, tenant, owner, and state. Record the expected durable state, response, and operator action before running it. During the exercise, deliberately introduce the condition where cross-tenant identifiers pass because the scope matches. The team must explain whether to retry, reject, compensate, roll back, or wait. Preserve denials by policy and unusual probing with enough dimensions to compare the expected and observed path. Finish by assigning ownership and documenting the threshold that would force the design to be reconsidered.
6. Rehearse sessions, refresh, and signing keys
Before sign-off, restate this article-specific claim in one sentence: Browser-readable long-lived bearer tokens magnify XSS, while key rotation and revocation remain lifecycle problems. Build a controlled exercise that includes key rollover, issuer outage, concurrent refresh, CSRF, logout, and revoked users. Record the expected durable state, response, and operator action before running it. During the exercise, deliberately introduce the condition where token material enters logs or attacker-chosen key URLs are fetched. The team must explain whether to retry, reject, compensate, roll back, or wait. Preserve unknown keys, refresh reuse, session anomalies, and sensitive-log scans with enough dimensions to compare the expected and observed path. Finish by assigning ownership and documenting the threshold that would force the design to be reconsidered.
Conclusion: keep authority and identity separate
Access tokens authorize APIs; ID tokens describe an authentication event to a client. Authorization Code with PKCE, exact redirects, issuer and audience checks, least-privilege scopes, and protected sessions form a modern baseline. Libraries implement cryptography, but teams still own flow selection, policy, token handling, telemetry, and incident response. The durable lesson is to state guarantees in language clients and operators can verify, then build the smallest mechanism that satisfies them under retries, concurrency, deployment, and partial failure. Revisit the decision when traffic, risk, or ownership changes.
Continue with REST API Design: Resource Contracts That Clients Can Trust to connect this topic to another production boundary. The Prime Axiom resource library collects practical implementation material.
Authoritative references
Security profiles evolve, so verify flow and token rules against the cited standards and the metadata of the configured issuer.


