Limits on HTTP Redirect URIs for OAuth in Production vs Local Development
0 reputation · 14 Jun 2023, 16:06 UTC
0 reputation · 14 Jun 2023, 16:06 UTC
Goal: configure an OAuth client so that the same redirect URI value works in a local development environment (using http://localhost:8080/callback) and in a production environment where the provider requires an HTTPS URI that exactly matches the registered value, including any trailing slash or query parameters.
Uncertainty: whether to enforce PKCE for all clients in production to protect against code interception, or to allow confidential clients to continue using only a client secret, which may be necessary for legacy systems that lack PKCE support.
What are the best practices for reconciling the HTTP vs HTTPS redirect URI requirement between local and production deployments without maintaining separate client registrations? Should PKCE be enforced for confidential clients in production, and how can organizations gracefully migrate legacy clients that cannot implement the code_verifier flow?
35275 reputation · 14 Jun 2023, 17:12 UTC
You cannot satisfy both constraints with a single registered redirect URI value, and you should not try. The standard practice is to register separate OAuth clients for development and production: the dev client carries http://localhost:8080/callback, and the production client carries the exact HTTPS URI. On PKCE: enforce it for all new clients, including confidential ones, and migrate legacy confidential clients on a staged timeline rather than leaving the exception open-ended.
Under RFC 6749, redirect URIs must be pre-registered and matched exactly — scheme, host, port, path, and trailing slash all count. Production-grade providers additionally require HTTPS for registered redirect URIs, with a deliberate exception for loopback addresses (http://localhost, http://127.0.0.1) so developers can test without TLS certificates. That exception is a development concession, not a production feature: many providers will reject or flag a loopback URI on a client that looks production-bound, and shipping it is a security risk regardless.
The common "works locally, fails in production" symptom is almost always a redirect_uri_mismatch caused by one differing character — a missing trailing slash, localhost vs 127.0.0.1, or a port the provider treats as part of the match. (Native apps under RFC 8252 are the exception: loopback redirects there use an ephemeral port and the provider ignores the port when matching.)
myapp-dev and myapp-prod.Note that limits on the number of redirect URIs per client, wildcard support, and IP-based hostnames are provider policy (Google, Microsoft Entra, Auth0, Okta all differ), not OAuth spec requirements — check your provider's console.
Yes — enforce PKCE in production even for confidential clients. The client secret and PKCE protect against different failures: the secret authenticates the client at the token endpoint, while PKCE binds the token exchange to the specific authorization request, blunting code-interception and code-injection attacks (for example via a compromised redirect or a leaked log). Current OAuth security best-practice guidance recommends PKCE for all client types, and the cost for a confidential client is small: generate a code_verifier, send its SHA-256 hash as code_challenge, and present the verifier at token exchange.
code_verifier. Most providers or your gateway can surface this.Trigger an authorize request with the exact production redirect URI and confirm it is accepted; then change one character and confirm you get a redirect_uri_mismatch-style error. Locally, test both localhost and 127.0.0.1 to learn which forms your provider treats as equivalent. One caveat: exact loopback handling and per-client URI limits vary by provider and change over time, so confirm against your provider's current documentation before locking the design.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 14 Jun 2023, 20:14 UTC
To build on the recommendation of separate client registrations, it is important to highlight why strict string matching is non-negotiable in production. Allowing partial matches or wildcards in the redirect URI can introduce Open Redirector vulnerabilities.
If a provider allows a wildcard (e.g., https://*.myapp.com/callback), an attacker who finds an open redirect on any subdomain can craft a link that leaks the authorization code to an external server. To verify your production security posture, check for the following:
redirect_uri differs by even a single trailing slash from the registered value.http, as loopback exceptions should never apply to production IDs.For legacy clients unable to support PKCE, the immediate priority should be rotating client secrets and ensuring they are stored in a secure vault rather than environment files.