Parsing and Validating OAuth Redirect URIs
OAuth 2.0 redirect URIs are URLs that authorization servers redirect users back to after granting or denying access. Parsing them correctly matters because a mismatch, even a trailing slash difference, causes the authorization to fail. RFC 6749 requires that redirect URIs in authorization requests exactly match a URI pre-registered with the authorization server.1 Consequently, servers must compare URIs byte-for-byte and not semantically, because two URIs that parse to the same result may still fail if their string representations differ.
The redirect URI carries the authorization code (or error) as a query parameter. For public clients such as mobile apps and SPAs, RFC 8252 and the PKCE extension address the risks of redirect URI interception.2 Understanding how the URI is parsed, validated, and compared prevents the most common OAuth integration failures.
Exact-match validation rules
Authorization servers must validate redirect URIs using exact string comparison per RFC 6749 Section 3.1.2. This means https://example.com/callback and https://example.com/callback/ are different URIs, and one will pass while the other will fail depending on which was registered. Consequently, uppercase and lowercase schemes and hosts are equivalent per RFC 3986 normalization, so http://EXAMPLE.COM/callback and http://example.com/callback are the same URI, but paths are case-sensitive. Building on this, query parameters in the registered URI must also match exactly, and the authorization request may not add parameters to the redirect URI beyond what the spec permits.1 Always normalize the scheme and host to lowercase before comparison while leaving the path and query string unchanged.
Fragment identifier restrictions
RFC 6749 forbids fragment identifiers in redirect URIs, so a registered URI like https://example.com/callback#section is invalid. The fragment component is handled by the browser, not the server, and the authorization code in the response query string would be exposed to the browser's fragment-handling logic. Building on this, implicit grant redirect URIs receive the access token as a fragment rather than a query parameter, but this is a server-side choice in the response, not something the client controls in the redirect URI registration. The authorization_code grant always delivers the code in the query string. Registering a redirect URI with a fragment will cause the authorization server to reject either the client registration or the authorization request, depending on when the validation occurs.
Parsing the callback URL
When your application's redirect endpoint receives a callback, extract the authorization code with url.searchParams.get('code') (JavaScript) or parse_qs(query)['code'][0] (Python). The state parameter must also be extracted and compared to the value your application stored before initiating the flow, and a mismatch indicates a CSRF attack. Consequently, if the error parameter is present instead of code, the authorization was denied or failed; display the error_description value to the user. Parse the entire URL before acting on any of its parameters, and never read parameters from raw string splits, because manual parsing misses edge cases like percent-encoded delimiters. After extracting the code, exchange it for an access token by making a server-side POST request to the token endpoint, never from the client side alone.
Loopback redirect URIs for native and desktop applications
RFC 8252 defines the OAuth 2.0 authorization framework for native applications, which cannot host a web-based redirect endpoint. Instead, native apps register loopback redirect URIs: http://127.0.0.1:{port}/callback or http://localhost:{port}/callback. The app starts a local HTTP server on a random port, opens the authorization URL in the browser, and receives the callback on the loopback interface. The port is chosen dynamically because the OS may assign any available port; the authorization server must accept any port value for the registered loopback URI.
Private-use URI schemes for mobile apps
Mobile apps can register custom URI schemes as redirect URIs: com.example.app://callback. When the authorization server redirects to this URI, the operating system launches the registered app. This approach avoids the loopback server but introduces a security consideration: any app can register the same custom scheme on some operating systems. iOS's Universal Links and Android's App Links solve this by associating the redirect URI with a specific app through domain verification, providing a more secure alternative to custom schemes.3
Domain verification is what makes App Links safer than custom schemes, because the binding lives in a hosted configuration the platform checks rather than in a local registration any app can claim. The trade-off is setup complexity: you must publish the verification artifact on the exact domain the URI uses, and the association only holds when that domain is reachable during the platform's check. Treat the custom scheme as a fallback for environments where you cannot host the verification file, and reserve App Links for production where the domain is under your control.
Redirect URI validation in multi-tenant OAuth providers
Multi-tenant authorization servers that serve many clients must validate redirect URIs efficiently. A naive implementation queries the database for each authorization request to find the registered URI, which adds latency to every login. Cache the registered redirect URIs in memory (Redis or an in-process cache) and validate against the cache. Invalidate the cache entry when a client updates its registration. For servers handling millions of authorization requests per second, the cache hit rate should approach 100%; a database lookup on every request creates a bottleneck that cascades through the entire login flow.
Preventing authorization code injection via redirect URI manipulation
An attacker who can manipulate the redirect_uri parameter can intercept authorization codes. If the server validates only the prefix of the registered URI (starts with https://example.com/callback), a redirect_uri prefix-match bypass lets an attacker register https://example.com/callback.evil.com and receive the code meant for the real client. Always validate the full redirect URI, including the path and query string. Some servers allow clients to register multiple redirect URIs; in that case, the authorization request must specify exactly one registered URI via the redirect_uri parameter, and the server must match it byte-for-byte against the registration database.4
OpenID Connect and additional redirect URI constraints
OpenID Connect extends OAuth 2.0 with identity tokens and adds additional redirect URI constraints. The post_logout_redirect_uri parameter, used after logout to return the user to the application, must also be pre-registered and validated with the same strictness as the authorization redirect URI. The id_token_hint parameter tells the authorization server which user is logging out, enabling it to verify that the post-logout redirect URI matches the client that initiated the session. Without this check, an attacker could craft a logout URL that redirects the user to a malicious site after logout, enabling session fixation on the next login.
Front-channel versus back-channel logout
OpenID Connect defines two logout mechanisms. Front-channel logout uses an iframe-based approach where the authorization server notifies all participating clients via their front_channel_logout_uri. Back-channel logout uses a direct HTTP POST to the client's back_channel_logout_endpoint with a logout token. The redirect URI validation applies to both: the front_channel_logout_uri must be pre-registered, and the back_channel_logout_endpoint must be a valid HTTPS URL that the authorization server can reach. Implementing both mechanisms ensures that a user logging out of one application is reliably logged out of all applications in the same session.5
When to use this
Parse and validate redirect URIs when implementing OAuth 2.0 authorization code flows, both server-side when receiving callbacks and client-side when constructing authorization request URLs for registration.
Examples
Extract OAuth callback parameters in JavaScript
// In the redirect callback page handler const url = new URL(window.location.href); const code = url.searchParams.get("code"); const state = url.searchParams.get("state"); const error = url.searchParams.get("error"); if (error) { console.error("Auth failed:", url.searchParams.get("error_description")); } else if (state !== sessionStorage.getItem("oauth_state")) { console.error("State mismatch — possible CSRF"); } else { // Exchange code for token }
Validate redirect URI on the authorization server (Python)
from urllib.parse import urlparse REGISTERED = "https://example.com/callback" def validate_redirect_uri(requested: str) -> bool: # Exact string match required per RFC 6749 if requested != REGISTERED: return False parsed = urlparse(requested) # Block fragments in redirect URIs return not parsed.fragment
- 1.
D. Hardt, Ed., "The OAuth 2.0 Authorization Framework," RFC 6749, IETF, October 2012. https://www.rfc-editor.org/rfc/rfc6749.html
- 2.
N. Sakimura, Ed., "Proof Key for Code Exchange by OAuth Public Clients," RFC 7636, IETF, September 2015. https://datatracker.ietf.org/doc/html/rfc7636
- 3.
W. Denniss and J. Bradley, "OAuth 2.0 for Native Apps," RFC 8252, IETF, October 2017. https://www.rfc-editor.org/rfc/rfc8252.html
- 4.
OWASP, "Testing for OAuth Authorization Server Weaknesses," owasp.org, accessed June 2026. https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/05-Authorization_Testing/05.1-Testing_for_OAuth_Authorization_Server_Weaknesses
- 5.
"OpenID Connect," Wikipedia, accessed June 2026. https://en.wikipedia.org/wiki/OpenID_Connect