3.2 OAuth 2.0 and OIDC: Delegated Authorization and Login
OAuth 2.0 enables resource owners to delegate limited API permissions to clients without sharing their passwords with them. OpenID Connect (OIDC) builds upon OAuth 2.0 by adding identity assertion semantics. Using an access token as proof of login or treating an ID token as a valid API credential crosses protocol boundaries.
Get Clear on Four Roles
Resource Owner: typically the user
Client: an application requesting delegated permissions
Authorization Server: authenticates the user and issues tokens
Resource Server: holds the protected APIA Client ID is a public identifier, not a password. Browser-based SPAs and native applications cannot reliably secure static client secrets, so they are classified as public clients. Backend services can only act as confidential clients if they can securely protect their credentials within a controlled environment.
Authorization Code + PKCE is the Default Interaction Flow
Simplified flow:
client generates code_verifier
└─ BASE64URL(SHA-256(ASCII(code_verifier))), no padding → code_challenge
browser → authorization endpoint
response_type=code, client_id, exact redirect_uri, state,
code_challenge, code_challenge_method=S256
scope=openid, nonce (OIDC)
authorization server → redirect with one-time code + state
client → token endpoint
grant_type=authorization_code, code, code_verifier,
client_id, redirect_uri; client authentication when requiredIf the authorization server correctly binds and verifies the challenge, PKCE prevents an attacker who has only the intercepted code, without the verifier, from redeeming it. The verifier must be regenerated for each request and securely stored within the client's context at the time of initiation, never hardcoded or reduced to a weak authentication method.
state binds the initial request to the callback, helping prevent login CSRF and response mix-ups; OIDC's nonce binds the ID token to the authentication request, helping prevent replay attacks. This example retains both for request correlation. RFC 9700 also permits PKCE to provide CSRF protection under conditions including confirmed server support and correct enforcement. That conditional substitution does not remove the need to validate callback context.
Redirect URIs normally require exact registration and matching. Native-app loopback IP callback ports have a narrowly defined exception; this does not permit arbitrary wildcards. Wildcards, open redirects, and loose string-prefix comparisons can route the code or token to attacker-controlled locations.
Check S256 Encoding
S256 uses unpadded Base64url of the raw SHA-256 digest, not its hexadecimal representation. This example includes the public test vector from RFC 7636 Appendix B. Keep each generated verifier within its authorization transaction; do not log it or send it to the authorization endpoint.
import base64
import hashlib
import re
import secrets
def pkce_challenge(verifier):
if not isinstance(verifier, str) or not re.fullmatch(r"[A-Za-z0-9._~-]{43,128}", verifier):
raise ValueError("invalid PKCE verifier")
digest = hashlib.sha256(verifier.encode("ascii")).digest()
return base64.urlsafe_b64encode(digest).rstrip(b"=").decode("ascii")
verifier = secrets.token_urlsafe(32)
challenge = pkce_challenge(verifier)
assert len(verifier) == len(challenge) == 43
assert pkce_challenge("dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk") == (
"E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
)This only tests generation and encoding, not an authorization server. Redemption must also enforce one-time codes, client and redirect_uri binding, and any required confidential-client authentication. PKCE does not replace a client secret.
OAuth 2.1 Is Still Not a Published RFC
As of September 5, 2026, Datatracker lists OAuth 2.1 draft-16 is still an IETF Internet-Draft. It consolidates practices such as Authorization Code with PKCE and removes flows such as implicit and resource owner password credentials, but it is not a final standard.
Production security baselines should be based on published RFCs such as RFC 9700 (OAuth 2.0 Security Best Current Practice): avoid using the implicit grant or Resource Owner Password Credentials grant, prevent authorization code injection and token replay attacks, and strictly limit token permissions.
Token Type Determines Validation Location
An access token is an authorization credential intended for a Resource Server and can be either an opaque random value or a JWT. The client should not rely on internal fields of the token to infer user login status.
An ID token represents the authentication result of an OIDC client, with its target audience set to the client. Validation must include at least the following:
- Determine the issuer from a trusted configuration, not by trusting the token’s self-reported issuer address;
- Allow only expected signing algorithms, verified against the issuer’s trusted public key set;
- Check
iss, confirmaudincludes this Client ID, and validate the authorized party as required for multiple audiences or a presentazp; - Validate
exp,iat, and account for reasonable clock skew; - Verify
nonceagainst the corresponding request; - Perform business-specific checks on
auth_time,acr, and similar claims to enforce authentication-assurance requirements.
When validating an access token, the Resource Server focuses on the issuer, its own audience, scope or authorization details, expiration time, revocation policies, and sender constraints. It should not equate a "valid JWT signature" with "permission to access any resource."
Refresh Tokens Are High-Value Long-Lived Credentials
If a refresh token is exposed in browsers or mobile apps, it may keep yielding access tokens until expiry or revocation. RFC 9700 requires authorization servers to use rotation or sender constraints for public-client refresh tokens to detect replay. Rotation issues a new token and invalidates the old one; the server must retain token-family relationships and define revocation after reuse. Legitimate concurrent refreshes also need explicit handling so races are not mistaken for theft.
Access tokens should follow the principles of minimal audience, minimal scope, and short validity periods. High-value systems can use mTLS or DPoP to bind access tokens to the sender's cryptographic key, reducing the usability of copied bearer tokens, though this still does not mitigate the risk of a fully compromised endpoint.
Frontend applications should avoid storing long-lived tokens in any script-readable location, such as localStorage. For traditional web applications, a Backend-for-Frontend (BFF) can keep OAuth tokens on the backend and expose only the minimal browser session state via a protected session cookie. The choice between approaches depends on the overall architecture; treating a BFF as a universal solution risks overlooking critical concerns like CSRF, session fixation, and backend lateral privilege escalation.
OIDC Discovery Also Requires a Trust Anchor
Discovery enables automated key discovery and rotation via JWKS, but the URL must originate from a pre-configured issuer or be validated through a strict discovery process. It is not permissible to directly make network requests to an arbitrary token's iss, as this could lead to SSRF attacks, key confusion, or malicious issuer takeover.
Key rotation must allow for a brief overlap between old and new signing keys, and must restrict refreshes for unknown kid. An attacker could generate a large volume of random kid, and we must not allow each failure to trigger an unbounded external JWKS request.
Process Validation
- Use Authorization Code + PKCE (S256) instead of implicit or ROPC?
- Is the Redirect URI exactly registered, with no open redirect vulnerabilities?
- Are
state, OIDCnonce, and PKCE verifier values generated and validated separately? - Are access tokens, ID tokens, and refresh tokens isolated by audience and intended use?
- Are the trusted issuer, algorithm, and audience fixed and explicitly defined?
- Are tokens scoped minimally, time-limited, revocable, or replay-detectable?
- Can browser scripts access long-lived credentials?
- Does the API continue to enforce resource-level authorization beyond token validity?
Continue with Authorization Models and Resource-Level Checks to decide which actions a principal may take on a specific resource.
References
- RFC 9700, Best Current Practice for OAuth 2.0 Security
- RFC 7636, Proof Key for Code Exchange
- OpenID Foundation, OpenID Connect Core 1.0
- IETF Datatracker, OAuth 2.1 Draft