Authentication flow diagram labeled Application and Identity Provider

OAuth Redirect URI Vulnerabilities: How a Small Validation Mistake Can Leak Authentication Tokens

spyboy's avatarPosted by

You click:

“Login with Google.”

You authenticate.

Google asks whether you want to continue.

You approve.

Then you’re redirected back to the application.

It looks completely normal.

But behind that simple flow is one of the most security-sensitive pieces of modern web authentication:

redirect_uri

It tells the identity provider:

“After authentication, send the user back here.”

That sounds harmless.

It isn’t.

If an application validates redirect URLs incorrectly, an attacker may be able to manipulate where authentication results are sent.

Depending on the OAuth flow and implementation, that can lead to:

  • Authorization-code leakage
  • Token exposure
  • Account compromise
  • Session compromise
  • Cross-account linking
  • OAuth phishing
  • Login CSRF
  • Authorization-code interception

And the scary part is that the attacker may never need to break the identity provider.

The identity provider may be functioning perfectly.

The vulnerability can exist entirely in the application’s redirect URI validation.


What Is OAuth?

OAuth is an authorization framework used by applications to obtain access to resources or establish delegated access.

You’ve probably seen:

Continue with Google
Continue with GitHub
Continue with Microsoft
Continue with Apple

A simplified authorization flow looks like:

User
Application
Identity Provider
User authenticates
Authorization granted
Redirect back to application
Application processes authorization result

The critical component is:

redirect_uri

What Is a Redirect URI?

A redirect URI is the destination where the identity provider sends the browser after authorization.

For example:

https://example.com/oauth/callback

The application registers this URI with the identity provider.

The authorization request might conceptually contain:

client_id=12345
redirect_uri=https://example.com/oauth/callback
response_type=code
scope=openid

The identity provider should only redirect to an approved destination.

That restriction is extremely important.


Why Does OAuth Care About the Redirect?

Imagine the identity provider authenticates the user successfully.

It generates:

authorization code

and sends the browser to:

https://example.com/oauth/callback?code=ABC123

The application receives the code and exchanges it for tokens.

The flow is:

Authentication
Authorization Code
redirect_uri
Application
Token Exchange

If an attacker can manipulate the redirect destination, the authorization code could potentially be delivered somewhere it shouldn’t be.


The Basic Vulnerability

A vulnerable application might accept:

https://example.com/oauth/callback

but incorrectly allow variations such as:

https://example.com/oauth/callback?next=...

or other attacker-influenced forms.

The problem is usually not:

“The URL contains parameters.”

The problem is:

The application fails to enforce the exact redirect URI security boundary.


Exact Matching Matters

Suppose the legitimate redirect URI is:

https://example.com/oauth/callback

A secure implementation should have a clearly defined policy for exactly which URI is allowed.

Dangerous validation often looks conceptually like:

Starts with:
https://example.com

That is not equivalent to:

Exactly:
https://example.com/oauth/callback

For security-sensitive redirects, loose string matching can be dangerous.


The Classic “Starts With” Mistake

Imagine a developer writes logic equivalent to:

if redirect_uri starts with:
https://example.com
allow

An attacker might try to construct a URL whose beginning appears legitimate but whose actual destination is not.

For example, the security question becomes:

Does the application validate the URL's actual origin?

or merely:

Does the string look like it starts with our domain?

Those are very different security models.


Why URL Parsing Is Hard

URLs have many components:

scheme://userinfo@host:port/path?query#fragment

For example:

https://user@example.com:443/login?next=/home

A developer who validates URLs using simple string operations can easily misunderstand which part represents the actual destination.

Security-sensitive URL validation should use a proper URL parser and explicit allowlisting rather than fragile string comparisons.


The Subdomain Problem

Suppose an organization owns:

example.com

and trusts:

login.example.com

A developer may think:

“Anything under example.com is safe.”

But subdomains can have different security properties.

For example:

trusted.example.com
old.example.com
dev.example.com
user-content.example.com

One compromised or attacker-controlled subdomain could potentially become relevant to an OAuth flow.

This is why OAuth redirect URIs should generally be narrowly scoped.


Wildcard Redirect URIs Are Dangerous

Imagine an application allows:

https://*.example.com/oauth/callback

That seems convenient.

But now every matching subdomain becomes part of the authentication trust boundary.

If one subdomain is:

  • abandoned
  • vulnerable
  • user-controlled
  • hosted by a third party
  • vulnerable to takeover

the OAuth configuration may inherit that risk.


OAuth and Subdomain Takeover

This is an interesting attack chain:

Forgotten subdomain
Subdomain takeover
Trusted OAuth redirect
Authorization response
Potential credential/token exposure

Neither vulnerability needs to be catastrophic alone.

Together, they can become significantly more serious.

This is why security researchers think about vulnerability chaining.


The Open Redirect Connection

Another dangerous combination is:

OAuth
+
Open Redirect

Suppose:

https://example.com/oauth/callback

is trusted.

But the callback itself redirects users based on an unsafe parameter:

https://example.com/oauth/callback?next=...

If the application can be made to redirect an authorization result toward an attacker-controlled destination, the redirect becomes part of the attack chain.

However:

An open redirect does not automatically mean OAuth token theft.

The exact OAuth implementation determines whether sensitive information can actually be exposed.


Authorization Code Flow

Modern OAuth deployments commonly use an authorization code.

The conceptual flow is:

User
Client
Authorization Server
Login
Authorization Code
Redirect URI
Client
Token Endpoint
Access Token

The authorization code is generally preferable to sending access tokens directly through the browser.

But the code still needs protection.


PKCE Makes a Huge Difference

PKCE stands for:

Proof Key for Code Exchange

It was designed to protect authorization-code flows against certain interception attacks.

The client creates a secret:

code_verifier

and derives:

code_challenge

The authorization request contains the challenge.

Later, when exchanging the authorization code, the client must provide the verifier.

Conceptually:

Client
├── code_challenge
Authorization Server
├── authorization code
Client
└── code_verifier
Authorization Server

If the verifier doesn’t match, the exchange should fail.


Why PKCE Matters

Suppose an attacker somehow obtains:

authorization_code

Without proper protections, they might attempt to redeem it.

With PKCE:

authorization_code
+
wrong verifier
=
rejected

This significantly reduces the impact of certain authorization-code interception scenarios.

But PKCE doesn’t fix every redirect URI vulnerability.


PKCE Is Not a Magic Shield

A common misconception is:

“We’re using PKCE, so redirect URI validation doesn’t matter.”

Wrong.

You still need:

  • Correct redirect URI validation
  • Proper state handling
  • Secure token handling
  • Correct client authentication where applicable
  • Exact authorization-server configuration

PKCE protects one important part of the flow.

It doesn’t make every OAuth implementation secure automatically.


The state Parameter

OAuth clients commonly use:

state

to bind an authorization response to the request that initiated it.

Conceptually:

User starts login
Application generates state
Authorization request
Identity provider
Callback + state
Application verifies state

If the state doesn’t match, the application should reject the response.


Why State Matters

Without proper state validation, applications can become vulnerable to certain forms of:

  • Login CSRF
  • Authorization response injection
  • Account-linking confusion

The basic security principle is:

The application should know that the OAuth response belongs to the login transaction the user actually initiated.


Login CSRF

Here’s a simplified example.

Imagine an attacker authenticates with their own identity provider account.

They obtain an authorization response.

Then they somehow cause a victim’s browser to process that response.

If the application doesn’t properly bind the authorization response to the victim’s login attempt, the victim could end up logged into the attacker’s account.

That sounds harmless.

It isn’t.

The victim might then upload:

  • Personal information
  • Private documents
  • Payment information
  • Messages
  • Sensitive account data

thinking they’re using their own account.

The attacker can later access the information stored in the account they control.

This is a powerful example of why OAuth security isn’t only about stealing tokens.


Account Linking Is Another Dangerous Area

Consider an application supporting:

Email/password
+
Login with Google

A user already has:

alice@example.com

If the application automatically links OAuth identities based solely on email without properly verifying ownership, account-linking vulnerabilities can arise.

The secure approach is to require an explicit, authenticated account-linking flow.


OAuth Redirect URI Validation Checklist

When assessing an OAuth implementation you own or are authorized to test, ask:

Is the redirect URI:

  • Exactly registered?
  • Strictly matched?
  • Scheme validated?
  • Host validated?
  • Port validated?
  • Path validated?
  • Normalized consistently?
  • Free from unexpected wildcards?

And:

Does the application:

  • Use PKCE?
  • Validate state?
  • Protect authorization codes?
  • Avoid tokens in URLs where possible?
  • Prevent open redirects?
  • Require explicit account linking?
  • Validate issuer and audience?

How Bug Bounty Researchers Analyze OAuth

If a bug bounty program explicitly permits OAuth testing, begin by mapping the normal flow.

Capture:

Authorization endpoint
Client ID
Redirect URI
State
PKCE parameters
Scope
Response type

Don’t immediately attempt to steal tokens.

First understand how the system is supposed to work.


Step 1: Capture a Normal Login

Start with:

Login with Google

or another supported identity provider.

Record the normal authorization request.

You’ll typically see something conceptually like:

client_id=...
redirect_uri=...
response_type=code
scope=...
state=...
code_challenge=...

Step 2: Identify the Registered Redirect

Determine which callback the application normally uses.

For example:

https://example.com/auth/callback

Now ask:

How strictly is this URI enforced?


Step 3: Look for Loose Validation

During authorized testing, researchers may examine how the application handles controlled variations.

The objective is not to redirect real users.

The objective is to determine whether:

Approved URI

is treated differently from:

Unexpected URI

and whether the identity provider or application rejects the variation.


Step 4: Test With Your Own OAuth Account

Use:

Researcher account
+
Researcher OAuth account

This allows you to safely verify:

  • Login binding
  • Redirect behavior
  • State handling
  • Account linking
  • Authorization-code handling

without touching another user’s identity.


Step 5: Prove the Security Boundary

A good OAuth finding should demonstrate something concrete.

For example:

Registered redirect
Unexpected redirect accepted
Authorization response reaches controlled endpoint
Security-sensitive information exposed

Or:

OAuth response
State not validated
Attacker-controlled authorization response accepted
Account-linking/login confusion

Don’t Confuse Reflection With Exploitation

Suppose you modify:

redirect_uri

and the application reflects it somewhere.

That alone does not prove:

“OAuth takeover.”

You need to establish:

Input
OAuth behavior
Sensitive data or authorization impact

Security reports should focus on the actual impact.


Common OAuth False Positives

Redirect URI rejected

Good.

Authorization server rejects unknown URI

Good.

URL reflected in an error message

Not necessarily vulnerable.

Open redirect exists

Interesting, but not automatically an OAuth vulnerability.

Authorization code appears in browser URL

Normal for code-based OAuth flows.

PKCE is present

Good—but other security controls still matter.


OAuth Authorization Code vs Access Token

These are not the same.

Authorization Code

Temporary credential used to obtain tokens.

Access Token

Credential used to access protected resources.

A secure architecture tries to minimize the exposure of both.

For browser-based applications, the authorization code flow with PKCE is generally preferable to legacy patterns that expose access tokens directly through the front channel.


Never Put Long-Lived Secrets in Front-Channel URLs

URLs can leak through:

  • Browser history
  • Server logs
  • Proxy logs
  • Analytics
  • Screenshots
  • Referrer information
  • Monitoring systems

That’s one reason OAuth implementations should carefully control what sensitive information travels through URLs.


OAuth and URL Fragments

Older OAuth flows sometimes placed access tokens in the URL fragment:

https://example.com/callback#access_token=...

Fragments aren’t sent to the server in the normal HTTP request, but browser-side JavaScript can access them.

Modern application design generally favors safer authorization-code-based patterns rather than exposing access tokens directly through the browser.


OAuth and Mobile Apps

Mobile applications introduce additional complexity.

Instead of:

https://example.com/callback

you may encounter:

myapp://callback

or platform-specific universal/app links.

Poorly configured custom URL schemes can introduce interception risks because other applications may attempt to register the same scheme.

Modern mobile OAuth guidance generally favors platform-supported mechanisms such as claimed HTTPS links where appropriate.


OAuth and Desktop Applications

Desktop apps face similar concerns.

A local application may use:

http://127.0.0.1:<port>/callback

for OAuth.

This can be secure when implemented correctly, but the application must carefully handle:

  • Random ports
  • State
  • PKCE
  • Local callback validation
  • Process lifecycle

Never assume:

“localhost automatically means safe.”


OAuth and Single Sign-On

Enterprise SSO makes redirect security even more important.

Imagine:

Employee
Company App
Identity Provider
SSO
Company App

If redirect handling is broken, the impact can potentially extend across multiple applications.

A single identity provider may authenticate users into:

Email
HR
CRM
Cloud
Developer tools
Internal dashboards

OAuth configuration is therefore part of the organization’s identity security boundary.


How Developers Should Secure OAuth Redirects

1. Use Exact Redirect URIs

Avoid overly broad patterns.

Prefer:

https://example.com/oauth/callback

over:

https://*.example.com/*

when possible.


2. Use PKCE

Especially for public clients and browser/mobile authorization flows.


3. Validate state

Generate unpredictable state values and verify them when the callback returns.


4. Prevent Open Redirects

An OAuth callback should not become a generic redirector.


5. Minimize Redirect Trust

Treat redirect destinations as security-sensitive configuration, not ordinary user input.


6. Avoid Silent Account Merging

Require proper verification before linking OAuth identities to existing accounts.


7. Protect Tokens

Don’t expose access or refresh tokens unnecessarily through:

  • URLs
  • Logs
  • Analytics
  • Client-side debugging

OAuth Security Checklist

Redirects

  • Exact redirect URI matching
  • No unnecessary wildcards
  • No arbitrary subdomains
  • No user-controlled callback destinations
  • No open redirect in callback flow

Authorization

  • Use PKCE
  • Validate state
  • Validate issuer
  • Validate audience where applicable
  • Validate authorization responses

Tokens

  • Short-lived access tokens
  • Secure refresh-token storage
  • Refresh-token rotation where appropriate
  • No sensitive tokens in logs
  • No unnecessary token exposure in URLs

Account Linking

  • Explicit linking
  • Verify account ownership
  • Don’t silently merge identities
  • Notify users of new linked accounts

A Realistic OAuth Attack Chain

A serious OAuth vulnerability often isn’t one bug.

It may look like:

Loose redirect validation
Open redirect
Authorization response exposure
Authorization-code theft
Missing PKCE / weak state handling
Code redemption
Account compromise

This is why security researchers look at the entire flow, not just individual parameters.


Why OAuth Bugs Are So Valuable in Bug Bounty

OAuth sits directly in the authentication layer.

A small mistake can affect:

  • Login
  • Account linking
  • Identity verification
  • SSO
  • Third-party access
  • Token issuance

That makes OAuth an excellent area for advanced bug-bounty research.

But it also means testing needs to be extremely careful.

Authentication vulnerabilities can affect real users quickly.


What Makes a Strong OAuth Bug Bounty Report?

A good report should contain:

1. Normal Flow

Explain how authentication normally works.

2. Vulnerable Parameter

Identify the specific component:

redirect_uri
state
client_id
scope

3. Expected Behavior

Explain what should happen.

4. Actual Behavior

Explain what actually happens.

5. Controlled Reproduction

Use your own accounts and infrastructure.

6. Security Impact

Explain exactly what an attacker gains.

7. Remediation

Recommend strict redirect validation and appropriate OAuth protections.


The Bigger Lesson

OAuth has made the internet dramatically more interconnected.

You don’t create a separate password for every service anymore.

You click:

Continue with Google

and suddenly one identity provider is participating in authentication across another application.

That convenience creates trust relationships.

And trust relationships create attack surfaces.

The most important OAuth security question is therefore:

Who is allowed to receive the authentication result?

If the answer is:

“Anyone who can make the URL look legitimate,”

you have a serious problem.


Final Takeaway

OAuth attacks often don’t look like traditional hacking.

There may be:

  • No password cracking
  • No SQL injection
  • No malware
  • No brute force

Instead, the attacker finds a tiny mistake in the authentication flow:

redirect URI
state
PKCE
account linking
token handling

and turns that mistake into something much bigger.

The key lesson is:

Authentication is only as strong as the weakest redirect and trust relationship around it.

For developers:

Use exact redirect URI matching, PKCE, state validation, secure token handling, and explicit account linking.

For bug bounty hunters:

Don’t stop when you find a suspicious redirect. Trace the entire OAuth flow and prove the actual security impact using accounts and infrastructure you control.

Because the most dangerous part of:

Login with Google

isn’t always the login.

Sometimes it’s:

Where Google sends you after the login.


Discover more from Spyboy blog

Subscribe to get the latest posts sent to your email.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.