Try the URL Encoder/Decoder

Why OAuth redirect_uri Errors Are Almost Always Encoding Problems — and How to Fix Them

OAuth redirect_uri errors are almost always URL encoding mismatches — the encoded URI sent in the authorization request must exactly match the registered URI, character for character. Here's the correct encoding for redirect_uri, why Base64 state parameters break CSRF checks when + decodes as space, the five different array encoding formats that different frameworks use, and the URL parser inconsistencies that enable SSRF attacks.

June 29, 2026 7 min read
Share: Facebook WhatsApp LinkedIn Email
Why OAuth redirect_uri Errors Are Almost Always Encoding Problems — and How to Fix Them

OAuth 2.0 authorization URLs are one of the most common places where URL encoding errors cause authentication failures — because the redirect_uri parameter must be percent-encoded precisely, and a single unencoded character or a double-encoded character produces a mismatch that rejects the entire authorization flow

The previous articles on this site covered URL encoding basics, edge cases in real applications, URL structure and open redirect vulnerabilities, URL design as API design, and encoding by context. This article addresses URL encoding in OAuth and authentication flows — specifically the exact encoding requirements for redirect URIs, state parameters, and the specific ways clients and servers disagree on what "encoded" means.


The OAuth redirect_uri problem: exact string matching

OAuth 2.0's redirect_uri security requirement is strict: the redirect URI in the authorization request must exactly match one of the pre-registered redirect URIs for the client application. This exact matching prevents redirect URI manipulation attacks where an attacker substitutes a different URI to capture the authorization code.

The encoding problem: "exactly match" means the encoded form must match the registered form. If you registered https://example.com/callback?next=/dashboard as your redirect URI and your code URL-encodes the ? and / in the path, you might send https://example.com/callback%3Fnext%3D%2Fdashboard — which looks like the same thing but is a different string. The authorization server rejects it.

The correct approach: the redirect_uri parameter in the OAuth request is the URI itself. The URI's query string components (like ?next=/dashboard) should be encoded as part of the URI value when it's embedded in the authorization URL's query string — this is the "URL inside a URL" encoding problem covered in the previous article.

Authorization URL:
https://auth.example.com/authorize
  ?client_id=your_client_id
  &redirect_uri=https%3A%2F%2Fexample.com%2Fcallback%3Fnext%3D%2Fdashboard
  &response_type=code
  &state=random_state_value

The redirect_uri value https://example.com/callback?next=/dashboard is URL-encoded as https%3A%2F%2Fexample.com%2Fcallback%3Fnext%3D%2Fdashboard — the entire URI is treated as a value within the outer URL's query string.


The state parameter: encoding requirements and CSRF protection

The state parameter in OAuth serves two purposes:

  1. CSRF protection: a random value that the server echoes back, which the client verifies to ensure the response corresponds to its own request
  2. Preserving application state: returning the user to where they were before authentication

The state parameter must be URL-safe — if it contains characters like +, =, or / (common in Base64-encoded values), these need to be encoded when embedded in URLs or use the Base64url encoding variant that avoids these characters.

A specific failure pattern: generating a state as standard Base64 (randomBase64()abc+def/ghi==), embedding it in the redirect URL without encoding, then trying to verify it after the authorization server returns it. The + signs get decoded as spaces by the receiving server, so the round-trip transforms abc+def/ghi== into abc def/ghi== — the CSRF check fails and the authentication is rejected.

The fix: use Base64url encoding (replacing + with - and / with _, omitting = padding) for the state value, which is URL-safe without further encoding.


Query string arrays: the encoding that has no standard

Sending arrays in URL query strings has no standard encoding, and different frameworks make different choices — a major source of interoperability problems:

PHP-style (used by many web frameworks): ?tags[]=javascript&tags[]=python&tags[]=go Or: ?tags[0]=javascript&tags[1]=python

Comma-separated (simpler, but loses ability to include commas in values): ?tags=javascript,python,go

Repeated key (the format specified in the URL standard's query string parsing rules): ?tags=javascript&tags=python&tags=go

JSON-encoded (most explicit but unusual in URLs): ?tags=%5B%22javascript%22%2C%22python%22%2C%22go%22%5D (The %5B is [, %5D is ], %22 is ")

When calling a third-party API that expects arrays, reading its documentation for which format it expects is essential — assuming the format your framework produces natively is dangerous. qs.stringify in Node.js, urllib.parse.urlencode in Python, and http_build_query in PHP all have different default behaviors for arrays.


URL parsing security: the authority confusion attacks

URL parsing is surprisingly complex, and inconsistencies between how different parsers interpret URLs enable security attacks:

The @ symbol in URLs: https://[email protected]/ — the @ in a URL separates userinfo from the host. This URL connects to example.com, not evil.com (the evil.com part is interpreted as username). But displayed in some contexts, it might look like the URL goes to example.com when it actually goes to evil.com. Different parsers handle this differently — some modern parsers reject credentials in URLs by default.

The # and ? interaction: https://example.com/path?query=value#fragment — the fragment (#...) is processed client-side only. Some URL parsers that try to extract the path may get confused by unusual ordering or encoding of these separators.

The double-slash confusion: https:///example.com or https://example.com//path — some parsers interpret triple-slash differently; double-slash in a path may be normalized to single slash by some servers but not others.

These parser inconsistencies are actively exploited in SSRF (Server-Side Request Forgery) attacks, where an attacker provides a crafted URL that one component in a system interprets as safe but another component executes as an attack.


Encoding for email links: the mailto: and tracking URL issues

Email marketing links typically involve multiple layers:

  1. The destination URL (the page being linked to)
  2. UTM parameters added to the destination URL
  3. A redirect/tracking URL wrapping the destination URL
  4. The tracking URL appearing in the email HTML

Each layer needs proper encoding:

  • The destination URL's ? and & must be preserved as-is (they're structural)
  • The entire destination URL (with UTM parameters) must be percent-encoded when embedded as a parameter in the tracking redirect URL
  • The tracking redirect URL must be properly encoded in the HTML href attribute (with & for any & characters)

Breaking any of these encoding layers produces a link that either doesn't track correctly, redirects to the wrong destination, or produces a 404 error — and these failures often aren't caught until campaign analytics show unexpected results.


How to use the URL Encoder/Decoder on sadiqbd.com

  1. For OAuth redirect URIs: encode the full redirect URI (including any query parameters it contains) as the value of the redirect_uri parameter in your authorization URL — the tool shows the correctly encoded form
  2. For debugging OAuth failures: decode a redirect_uri from a failing request and compare it against the registered URI exactly — encoding differences are the most common cause of "redirect_uri mismatch" errors
  3. For multi-layer URL encoding: encode the inner URL first, then embed that encoded string as a parameter in the outer URL — the tool handles the encoding correctly when you encode each layer sequentially

Frequently Asked Questions

Why does my OAuth redirect_uri work in development but fail in production? Usually a mismatch between the registered URI and what the code sends. Common causes: the development server uses http://localhost:3000/callback (registered), but production sends https://app.example.com/callback (a different URI that isn't registered). Or the production URI has a trailing slash and the registration doesn't. Or the application adds query parameters dynamically (like ?next=/dashboard) that weren't in the registered URI. The fix is always: verify the exact string being sent (URL-decoded) and ensure it matches one of the registered redirect URIs character-for-character.

Is the URL Encoder/Decoder free? Yes — completely free, no sign-up required.

Try the URL Encoder/Decoder free at sadiqbd.com — percent-encode and decode URLs for any context instantly.

Share: Facebook WhatsApp LinkedIn Email

URL Encoder/Decoder

Free, instant results — no sign-up required.

Open URL Encoder/Decoder →
Similar Tools
JSON Formatter Hash Generator Regex Tester Color Converter Random String Generator REST API Checker Cron Explainer JSON Unescape & Cleaner
URL Encoding Edge Cases That Break Real Applications
Developer
URL Encoding Edge Cases That Break Real Applications
URL Structure: Query String Parsing Ambiguities, Punycode, and Open Redirect Vulnerabilities
Developer
URL Structure: Query String Parsing Ambiguities, Punycode, and Open Redirect Vulnerabilities
URL Design as API Design: REST Conventions, Versioning Strategies, and the Long-Term Cost of Changing URLs
Developer
URL Design as API Design: REST Conventions, Versioning Strategies, and the Long-Term Cost of Changing URLs
URL Encoding Context: Why a URL Inside Another URL, in HTML, and in a Shell Command All Need Different Treatment
Developer
URL Encoding Context: Why a URL Inside Another URL, in HTML, and in a Shell Command All Need Different Treatment