OAuth Authorization Code QA: Redirect URIs, State, PKCE, Tokens.
OAuth authorization code QA verifies one bound transaction across the browser, client application, authorization server, token endpoint, resource server, and local session. A.

OAuth authorization code QA verifies one bound transaction across the browser, client application, authorization server, token endpoint, resource server, and local session. A successful provider sign-in is only the happy path. Release evidence must also prove redirect restrictions, transaction binding, PKCE enforcement, code single use, issuer checks, token handling, scope limits, and safe failure behavior.
Use nonproduction clients, synthetic identities, minimal scopes, and controlled redirect domains. Never place client secrets, authorization codes, code verifiers, access tokens, refresh tokens, session cookies, or real account details in screenshots, URLs, logs, tickets, or fixtures. Record hashes and safe correlation IDs instead of reusable credentials.
Map Roles And Trust Boundaries
Identify the resource owner, browser, OAuth client, authorization server, token endpoint, resource server, local session service, proxy, secrets store, and provider administrator. Mark front-channel redirects separately from back-channel requests. Each crosses different trust boundaries and exposes different data.
Document which component creates transaction state, generates PKCE material, validates issuer and callback, exchanges the code, stores tokens, requests resources, and creates the application session. A library can implement protocol mechanics, but the application still owns registration, configuration, storage, error handling, and authorization decisions.
Pin Provider Metadata
Obtain issuer and endpoint information from an approved configuration or authenticated discovery document. Verify the expected issuer, HTTPS endpoints, supported response types, token authentication method, and PKCE support. Do not let an arbitrary login parameter choose a discovery URL or token endpoint.
Cache metadata according to a deliberate policy and test rotation or temporary unavailability. For clients supporting multiple issuers, RFC 9700 requires a mix-up defense. Verify the authorization response is associated with the issuer and endpoints selected when the transaction began.
Register Exact Redirect URIs
Register the smallest necessary set of HTTPS callbacks for each environment. RFC 9700 calls for exact string matching, with a defined exception for localhost ports in native applications. Test scheme, host, port, path, case, query, trailing slash, encoded characters, subdomain, and lookalike-domain changes.
Production clients should not accept preview, staging, wildcard, or developer callbacks unless the provider and deployment have a narrowly justified separate registration. Confirm invalid client and redirect combinations do not redirect to an untrusted destination. Remove open redirectors from callback hosts and post-login return paths.
Create One Transaction Record
Before redirecting, create a short-lived server-side transaction bound to the initiating browser session. Store the expected issuer, redirect URI, requested scope, PKCE challenge context, safe return destination, creation time, and one-time state identifier. Keep sensitive values out of browser-readable storage when the architecture permits.
Give each attempt a distinct identity. Starting a second login in another tab should not overwrite the first transaction silently. Define whether both can complete, only the latest remains valid, or each tab has independent state, then test that behavior with parallel sessions.
Generate PKCE Correctly
Generate a high-entropy transaction-specific code verifier and derive the S256 code challenge according to RFC 7636. Do not use a constant verifier, a user identifier, timestamp, or reusable application secret. Send only the challenge and method in the authorization request; retain the verifier for the token exchange.
RFC 9700 requires PKCE for public clients and recommends it for confidential clients. Test missing challenge, unsupported method, altered challenge, missing verifier, wrong verifier, reused verifier, and downgrade attempts. A token request containing a verifier must not succeed when the original authorization request had no bound challenge.
Protect State And Issuer Binding
Use a one-time state value securely bound to the initiating user agent when state provides CSRF protection or carries application state. Protect any embedded return destination from tampering. Do not treat state as a general open redirect parameter after the callback.
RFC 9700 explains that confirmed PKCE support can provide CSRF protection in defined cases, while OpenID Connect nonce has a related role for ID tokens. Implement the mechanism required by the exact protocol profile, then test missing, swapped, replayed, cross-browser, and cross-session values. Do not assume the presence of a parameter proves validation.
Build The Authorization Request
Send the registered client ID, exact redirect URI, authorization code response type, minimal approved scopes, state or required transaction binding, and PKCE challenge. Add provider-specific parameters only when documented and reviewed. Encode every value with a standards-compliant URL builder.
Inspect the final URL for duplicate parameters, unsafe concatenation, leaked internal state, excessive scopes, and user-controlled endpoint changes. Avoid placing secrets in the authorization request. Test long return destinations and Unicode input so application state cannot break parsing or alter the callback target.
Handle The Callback Safely
Accept callbacks only on the registered route and expected method. Parse the response once, reject duplicate security parameters, locate the short-lived transaction, and validate state, issuer binding, redirect context, and error shape before using the code. Do not create a session merely because a code parameter exists.
Keep callback pages free of third-party scripts and outbound links that could receive sensitive referrer data. Use deliberate Referrer-Policy and cache controls. Remove callback parameters from the visible URL through a safe server redirect after processing, without converting an untrusted return value into an open redirect.
Exchange Codes Back Channel
Send the authorization code, matching redirect URI when required, client authentication appropriate to the client type, and original PKCE verifier directly to the configured token endpoint over TLS. The browser must not perform a confidential client exchange or receive a client secret.
Apply strict timeouts, certificate validation, bounded response sizes, and controlled retries. Authorization codes are short-lived and single use, so blind replay after an uncertain network failure can create confusing outcomes. Correlate the provider response without logging the code or verifier. An API testing workspace helps separate environments and assertions.
Validate Token Responses
Require the expected status, content type, response schema, token type, scope, and expiration fields. For OpenID Connect, validate the ID token signature, issuer, audience, nonce where used, time claims, and authorized party rules through a maintained library and trusted key configuration.
Do not infer application authorization solely from a provider profile or an unvalidated token payload. Reject missing, malformed, oversized, unexpected-algorithm, wrong-issuer, wrong-audience, expired, and cross-client responses. Handle key rotation without accepting an arbitrary key URL supplied inside an untrusted token.
Restrict Scopes And Resources
Request the smallest scopes and resource audience needed for the feature. Confirm the consent screen matches the request and the returned scope does not silently broaden application privileges. Separate authentication from authorization: signing in identifies an account, while local roles decide what that account may do.
Test denied optional scopes, partial grants, changed consent, revoked access, and tokens presented to the wrong resource server. The API must verify token audience, issuer, expiry, and required scope rather than accepting any syntactically valid bearer value.
Create The Local Session
Map the verified external subject and issuer to one local account using a stable composite identity. Avoid joining accounts by an unverified email claim. Apply explicit linking, invitation, tenant, domain, and disabled-account policies before creating a local session.
Rotate the local session identifier after authentication, set Secure, HttpOnly, SameSite, path, domain, and expiry controls appropriate to the architecture, and retain only the token material the application needs. Test account switching, parallel providers, disabled users, changed email addresses, and existing sessions.
Store And Refresh Tokens
Prefer server-side encrypted storage with least-privilege access for refresh tokens and long-lived access. Keep browser exposure as small as the architecture allows. Define token rotation, expiry, revocation, provider disconnect, and incident response. Never store tokens in analytics, error messages, or ordinary application logs.
Test refresh success, expiry, revocation, rotation, duplicate refresh, network uncertainty, and provider errors. RFC 9700 provides current security guidance for refresh-token protection. A failed refresh should end or degrade the local session predictably rather than loop indefinitely or fall back to a broader credential.
Test Errors And Cancellation
Exercise user denial, provider error, invalid scope, login requirement, consent requirement, unavailable provider, token timeout, malformed JSON, and local account rejection. Display a safe actionable message without exposing provider internals, codes, tokens, client secrets, stack traces, or account existence.
Keep protocol errors separate from application authorization failures. A user who authenticates successfully but lacks local access should not receive a session. Verify safe return navigation and avoid automatic retry loops that repeatedly redirect the browser or flood the provider.
Exercise Replay And Concurrency
Replay a callback, authorization code, state value, and token response. Use two browsers, two tabs, two local sessions, and two issuers. A completed transaction must not complete again, and one browser must not consume another browser’s transaction. Authorization codes should fail after first redemption.
Race two callback submissions and two token exchanges. Exactly one local outcome should commit, with every losing path failing safely. Test browser back, refresh, copied callback URLs, message scanners, and delayed redirects. Apply the same evidence mindset used in replay defense, while respecting OAuth’s own protocol rules.
Log Without Leaking Credentials
Record a safe transaction ID, provider identifier, client configuration version, event stage, outcome category, latency, requested and granted scope categories, local account decision, and session creation result. Redact query strings and authorization headers by default. Never log codes, verifiers, tokens, secrets, cookies, or full identity claims.
Alert on redirect mismatches, state failures, issuer mismatches, repeated code redemption, PKCE errors, token endpoint spikes, scope changes, account-linking conflicts, refresh failures, and provider outages. Limit log access and retention, because even redacted identity events can reveal sensitive account relationships.
Run The Release Matrix
Create a matrix for provider metadata, registration, exact redirects, state, PKCE, issuer binding, callback parsing, code exchange, token validation, scope, account mapping, session creation, refresh, errors, replay, concurrency, logging, deployment, and rollback. Save expected and observed outcomes with build and configuration identifiers.
Block release for open redirects, loose callback matching, missing transaction binding, PKCE downgrade, issuer mix-up, code replay, browser-exposed secrets, unvalidated tokens, overbroad scope, unsafe account linking, session fixation, token leakage, or non-auditable failure. The Full Stack Web Development course can strengthen the browser, API, identity, testing, and deployment skills behind this gate.
FAQ
Is state still required when PKCE is used?
It depends on the protocol profile and confirmed provider support. RFC 9700 allows robust PKCE to provide CSRF protection in defined cases, while state may still carry protected application state.
Should confidential web clients use PKCE?
RFC 9700 recommends PKCE for confidential clients because it protects against authorization-code misuse and injection.
Can the callback redirect anywhere after login?
No. Post-login destinations must be constrained and integrity-protected so the client does not become an open redirector.
Want to Build Practical Technology Skills?
Explore RisingEdge courses designed to help students learn real skills, build projects, and prepare for career opportunities.



