OAuth 2.0
What You Will Learn
- How the OAuth 2.0 authorization flow works
- What the
stateparameter does and why it is critical - How CSRF attacks on OAuth flows work
- How to prevent OAuth CSRF vulnerabilities
What Is It?
OAuth 2.0 is an authorization framework that lets applications access resources on behalf of a user — without sharing the user’s password. It is the standard behind “Login with Google”, “Login with GitHub”, etc.
OAuth has several security pitfalls. The most common is missing or unverified state parameter protection.
Normal OAuth Flow
- User clicks “Login with Google”
- App redirects user to Google OAuth URL
- User authenticates with Google
- Google redirects back with a
code - App exchanges
codefor user identity
The code links the user’s Google account to their app account.
CSRF Attack in OAuth — Login CSRF / OAuth Misbinding
This attack exploits OAuth flows when the state parameter is missing or not verified.
The Vulnerability
If the app does not use or verify a state parameter, it cannot verify that the same user who started the login flow is the one completing it.
Step-by-Step Attack
Scenario: HR web app, attacker wants access to victim’s account using attacker’s own Google account.
Step 1 — Attacker initiates OAuth
Attacker clicks “Login with Google”. Generated URL:
https://accounts.google.com/o/oauth2/v2/auth?
client_id=HR_APP
&redirect_uri=https://hr-app.com/callback
&response_type=code
Step 2 — Attacker captures callback
After login, Google redirects to:
https://hr-app.com/callback?code=ATTACKER_CODE
This ATTACKER_CODE is tied to the attacker’s Google account. Attacker copies this URL instead of completing login.
Step 3 — Attacker sends crafted link to victim
https://hr-app.com/callback?code=ATTACKER_CODE
Sent via phishing email, hidden redirect, or malicious site.
Step 4 — Victim visits the link
Victim is already logged into the HR app. Browser sends session cookies + request to /callback.
Step 5 — App accepts it blindly
App processes code=ATTACKER_CODE:
- Exchanges it with Google
- Gets attacker’s identity
- Links it to victim’s account
Result
Victim’s account is now linked to the attacker’s Google account. The attacker can log in as the victim using Google and gains access to victim’s data.
Root Cause
The app assumes: “The user completing the OAuth flow is the same one who started it.” This assumption is false without verification.
Mitigation: The state Parameter
Step 1 — Generate state
const state = crypto.randomUUID();
Store in cookie or session.
Step 2 — Include in OAuth request
https://accounts.google.com/o/oauth2/v2/auth?
...
&state=RANDOM_123
Step 3 — Google returns state
https://hr-app.com/callback?code=XYZ&state=RANDOM_123
Step 4 — Verify state
if (req.query.state !== cookie.state) {
throw new Error("Invalid state — possible CSRF attack");
}
Why This Works
Attacker sends:
https://hr-app.com/callback?code=ATTACKER_CODE&state=ATTACKER_STATE
Victim has:
cookie.state = VICTIM_STATE
Mismatch — request rejected.
Key Insight
This attack does not steal credentials. It forces the victim to log in as the attacker — linking the attacker’s identity to the victim’s account.
Impact: Account takeover, unauthorized data access, CRM and email exposure.
One-line takeaway: OAuth without state cannot guarantee request integrity and is vulnerable to CSRF.