Redirect URIs in OAuth 2.0
It looks like the most boring line in your OAuth setup screen — just a URL you paste into a form. In reality, it's one of the single most important security checks in the entire protocol, and getting it wrong is one of the most common ways real apps get breached.
Imagine ordering a package and telling the courier, “just leave it at my address” — but never specifying which address. The courier would have no way to know whether “my address” means your actual home, or the empty lot next door that a stranger is now standing in, waving and claiming to be you. A redirect URI is how OAuth 2.0 avoids exactly that ambiguity: it’s the pre-registered, exact address the Authorization Server is allowed to send sensitive information back to, and nowhere else. This article explains what redirect URIs are, why they must match exactly, and what goes wrong — sometimes catastrophically — when that matching is loose.
WWhat a Redirect URI Is and Why It Exists
A redirect URI is the web address the Authorization Server sends the user’s browser back to once login and consent are finished — and it must be a known, trusted address, agreed upon in advance.
Recall the shape of a typical OAuth 2.0 login: your browser is sent away from the Client’s app to the Authorization Server’s login and consent screen, and then, once you approve access, your browser needs to be sent back to the Client so the flow can continue. The redirect URI is the answer to the question “back to where, exactly?” It’s a specific URL — such as https://tripplanner.com/oauth/callback — that the Client registers with the Authorization Server ahead of time, during setup, long before any real user ever logs in.
Think of checking into a hotel and being asked, “if we need to send a confidential document to your room, which room number should we use?” You tell the front desk “room 412,” and from that moment on, hotel staff will only ever deliver that document to room 412 — never to whichever room someone claims to be in at the door. The redirect URI is that pre-agreed room number for OAuth’s most sensitive delivery: the authorization code or token.
This pre-registration step matters enormously because the authorization code (and in some older flow variants, the access token itself) is delivered through the browser’s redirect. If an attacker could trick the Authorization Server into sending that code to a URL of the attacker’s choosing instead of the real Client, the attacker could intercept it and potentially gain access to the victim’s account.
The redirect URI isn’t just a convenience setting — it’s a security boundary. The Authorization Server checks every incoming request’s redirect URI against the exact list registered by the Client, and refuses to proceed if there’s no exact match.
EExact Matching: Why “Close Enough” Isn’t Good Enough
The single most important rule about redirect URIs is that the address used in a live login attempt must match a pre-registered address exactly — not approximately, not “close enough,” but character for character.
This means https://tripplanner.com/callback and https://tripplanner.com/callback/ (note the trailing slash) are technically two different URIs, and a strict Authorization Server will treat them as such. The same goes for the difference between http:// and https://, a different subdomain, a different port number, or extra query parameters tacked onto the end. This might feel overly strict at first, but every one of these small differences is a door that a loosely configured system could otherwise leave open.
Picture a bank check that must be deposited into “Account #4471-002” exactly. A teller who accepts “Account #4471-002 ” with a trailing space, or “account #4471-002” in a different case, might be treating two technically different account identifiers as if they were interchangeable — and if the bank’s systems aren’t careful, money meant for you could quietly end up somewhere else entirely.
| Registered Redirect URI | Attempted Redirect URI | Should It Match? |
|---|---|---|
| https://tripplanner.com/callback | https://tripplanner.com/callback | Yes — identical |
| https://tripplanner.com/callback | https://tripplanner.com/callback/ | No — trailing slash differs |
| https://tripplanner.com/callback | http://tripplanner.com/callback | No — different scheme (http vs https) |
| https://tripplanner.com/callback | https://evil.com/callback?redirect=tripplanner.com | No — entirely different host |
New developers sometimes register a wildcard pattern like https://tripplanner.com/*, expecting it to safely cover every page on their own site. Most modern Authorization Servers explicitly forbid or discourage broad wildcards precisely because a single vulnerable page anywhere under that pattern — even one the developer forgot existed — becomes a usable target for attackers.
HHow the Redirect URI Fits Into the Login Flow
The redirect URI shows up twice in a typical OAuth 2.0 login: once when the Client kicks off the request, and once when the Authorization Server sends the user back.
Client Registers Its Redirect URI
During setup — long before any user logs in — the developer registers the exact callback URL with the Authorization Server, e.g. https://tripplanner.com/oauth/callback.
Login Request Includes the Same URI
When a real user clicks “Connect,” the Client’s request to the Authorization Server includes that same redirect URI as a parameter, declaring “send the result back here.”
The Authorization Server Verifies the Match
Before showing any login or consent screen, the Authorization Server checks the URI in the request against its registered list. If there’s no exact match, it stops immediately and shows an error instead of proceeding.
User Logs In and Consents
Assuming the match is valid, the user sees the normal login and consent screen and approves access as usual.
Browser Is Redirected Back With the Code
The Authorization Server sends the user’s browser to the verified redirect URI, attaching the authorization code as a query parameter, completing the round trip.
sequenceDiagram
participant U as User's Browser
participant C as Client (TripPlannerApp)
participant AS as Authorization Server
C->>AS: Auth request incl. redirect_uri
AS->>AS: Check redirect_uri against registered list
alt No exact match
AS-->>U: Show error, stop flow
else Exact match found
AS->>U: Show login + consent screen
U->>AS: Approve access
AS->>U: Redirect to registered redirect_uri + code
U->>C: Deliver authorization code
end
AAttacks That Exploit Weak Redirect URI Checks
Loose redirect URI validation is one of the most consistently exploited weaknesses across real-world OAuth deployments. Understanding the attack helps explain why the rules feel so strict.
How It Works
An attacker crafts a malicious login link where the redirect URI parameter points to a page on the legitimate site that itself forwards traffic elsewhere — for example, a poorly secured “click here to leave this site” page. If the Authorization Server only checks that the domain matches, without checking the full exact path, the authorization code can be silently forwarded to the attacker’s own server through that secondary redirect.
Why It’s Dangerous
Once the attacker has the authorization code, they can exchange it for an access token themselves, gaining access to the victim’s account data as if they were the legitimate app.
The Fix
Authorization Servers require exact, full-path matching (not just domain matching) precisely to close this door, and well-built Clients avoid having any open-redirect pages anywhere near their registered callback paths.
What Strict Matching Protects Against
- Authorization codes being silently forwarded to attacker-controlled servers
- Malicious apps impersonating a legitimate Client to intercept tokens
- Subtle typo-squatting or path manipulation tricks going unnoticed
Practical Costs of Strictness
- Developers must remember to register every environment separately — localhost for development, staging, and production each need their own exact entries
- Moving a callback path (say, from /callback to /oauth/callback) requires updating the registration everywhere at once
- Native mobile apps need special handling since they don’t always have a normal website URL to redirect to
RRedirect URIs for Mobile and Desktop Apps
Native apps don’t run inside a normal website address bar, so they need slightly different redirect URI patterns to bring the user’s browser back into the app after login.
Two common approaches solve this. The first is a custom URL scheme, such as tripplannerapp://oauth/callback, which the operating system recognizes and routes directly back into the installed app instead of to a website. The second, increasingly preferred approach is a loopback address like http://127.0.0.1:PORT/callback, where the app temporarily runs a tiny local web server on the user’s own device just long enough to catch the redirect.
Real Example: Native Mobile Login
When a mobile banking app opens your device’s browser for login instead of using an embedded webview, and then automatically switches back to the app after you approve access, it’s very likely using one of these two redirect patterns behind the scenes — custom scheme or loopback — rather than a standard https:// web address.
Custom URL schemes can, in some operating systems, be registered by more than one installed app, which creates a risk that a malicious app could claim the same scheme and intercept the redirect meant for the legitimate one. This is one of several reasons public clients are also strongly encouraged to use PKCE alongside careful redirect URI configuration — PKCE ensures that even if the code is intercepted, it can’t be exchanged for a token without the original app’s dynamically generated secret.
FFrequently Asked Questions
SSummary and Key Takeaways
What to Remember
- A redirect URI is the pre-registered, exact web address the Authorization Server is allowed to send the authorization code back to after login and consent.
- Matching must be exact — scheme, host, port, and path all need to match character for character, with no wildcards allowed by default.
- Loose or wildcard redirect URI validation is one of the most commonly exploited weaknesses in real-world OAuth implementations, often enabling authorization-code theft.
- Every environment (local development, staging, production) needs its own exact redirect URI registered separately, rather than relying on one broad pattern.
- Native mobile and desktop apps typically use custom URL schemes or loopback addresses instead of a normal
https://web address, and benefit further from PKCE for extra protection. - The redirect URI check and the client secret check protect against two different risks: one ensures the code goes to the right place, the other proves who’s redeeming it.