Back to Blog
2026-03-22

OAuth Token Theft: Why Your SSO and MFA Won't Save You

RFC 9700 just codified years of OAuth breaches. Learn how token theft, consent phishing, and open redirects bypass your authentication controls—and how to actually defend against them.

OAuth Token Theft: Why Your SSO and MFA Won't Save You

THREAT BRIEFING

In January 2025, the IETF published RFC 9700—the first major update to OAuth security best practices since 2020. The document doesn't introduce new features. It codifies lessons learned from years of real-world breaches: Booking.com's open redirect vulnerability, Google's domain inheritance flaw, Microsoft's ongoing battle with consent phishing campaigns. Every vulnerability in this RFC represents attacks that succeeded in production environments.

Most security teams believe their SSO and MFA protect them from OAuth attacks. Here's the uncomfortable truth: OAuth tokens function independently of your authentication controls. Once an attacker obtains a valid token through consent phishing, token theft, or third-party compromise, they bypass SSO and MFA entirely. The token is the key, and whoever holds it gains access—regardless of where they're connecting from or what device they're using.

Real-World Impact: The Salesloft-Drift Breach

A third-party OAuth integration compromise at Salesloff affected 700+ organizations. The attackers didn't need passwords or MFA codes—they simply abused existing OAuth grants to access connected Salesforce instances. The breach exposed how OAuth integrations create attack paths one hop away from your core environment.

The Bearer Token Problem: No Sender Validation

OAuth 2.0 bearer tokens are cryptographic proof of authentication. Present one to an API, and you get access. The fundamental flaw? Bearer tokens provide absolutely no sender validation. A token stolen from a developer's laptop in San Francisco works just as well from a server in Moscow. No reauthentication required. No device binding. No geographic checks.

This design decision made OAuth scalable and implementable across heterogeneous systems. It also created a massive attack surface. Token theft is now the primary vector for API account takeovers, and traditional security controls are blind to it.

$1.2B
Financial Losses
From OAuth-related breaches in 2024-2025
1.1M
Records Exposed
Allianz Life Salesforce compromise via OAuth
700+
Organizations Affected
Salesloft-Drift third-party compromise
34%
YoY Increase
In secrets sprawl including OAuth tokens

Attack Vector #1: Consent Phishing

Consent phishing exploits the OAuth consent screen—that familiar dialog asking users to grant an app permission to access their data. Attackers create malicious applications with legitimate-sounding names, trick users into granting permissions, then use those OAuth grants to access corporate data indefinitely.

Microsoft has been fighting this battle for years. Attackers register apps with names like "Microsoft Teams Integration" or "OneDrive Sync Tool" in Azure AD. Users, conditioned to click "Accept" on permission dialogs, grant access without realizing they've handed their credentials to an attacker. The OAuth tokens issued are valid for months, often with refresh tokens that provide persistence even after password changes.

⚠️ Why Consent Phishing Works

Users are trained to accept permission prompts. Corporate security tools rarely monitor OAuth grants in real-time. And the malicious apps often use Microsoft's own infrastructure, making them appear legitimate in audit logs. By the time anyone notices, the data is already exfiltrated.

Attack Vector #2: Open Redirect Exploitation

The OAuth authorization flow involves multiple redirects. The user clicks "Authorize," gets redirected to the identity provider, authenticates, then gets redirected back to the application with an authorization code. If the redirect_uri parameter isn't strictly validated, attackers can steal those authorization codes.

Weak redirect URI validation is everywhere. Substring matching. Prefix matching. Wildcard subdomains. Each creates an opening for code interception. An attacker crafts a malicious OAuth URL that uses a legitimate client ID but redirects to their own server. The user sees a familiar login page, enters credentials, and the authorization code gets delivered to the attacker instead of the legitimate application.

Here's how a vulnerable redirect_uri check typically fails:

# VULNERABLE: Prefix matching allows subdomain takeover
def validate_redirect_uri(uri, allowed_uris):
    for allowed in allowed_uris:
        # DANGEROUS: "https://app.example.com" matches "https://app.example.com.evil.com"
        if uri.startswith(allowed):
            return True
    return False

# SECURE: Exact matching only
def validate_redirect_uri_secure(uri, allowed_uris):
    return uri in allowed_uris  # Exact match required

Defensive Strategy: What Actually Works

Static configuration reviews catch vulnerabilities at deployment. They don't catch runtime exploitation. Behavioral detection is the only reliable way to identify OAuth abuse after the fact.

Monitor for these patterns:

  1. Impossible travel: Same token used from geographically distant locations within impossible timeframes
  2. Off-hours access: OAuth tokens used outside normal business hours for user accounts
  3. New device fingerprints: Tokens presenting from previously unseen user agents or IP ranges
  4. Scope escalation: Refresh token requests asking for broader permissions than originally granted
  5. Third-party app sprawl: New OAuth applications with high-privilege scopes appearing in your tenant

PKCE (Proof Key for Code Exchange) isn't optional anymore—it's mandatory per RFC 9700. It binds authorization codes to the specific client instance that requested them, preventing interception attacks even if the redirect is compromised.

# PKCE Implementation Example
import secrets
import hashlib
import base64

def generate_pkce_challenge():
    """Generate PKCE code_verifier and code_challenge"""
    # Generate random code_verifier (43-128 chars)
    code_verifier = base64.urlsafe_b64encode(
        secrets.token_bytes(32)
    ).decode('utf-8').rstrip('=')
    
    # Create code_challenge using S256 method
    code_challenge = base64.urlsafe_b64encode(
        hashlib.sha256(code_verifier.encode()).digest()
    ).decode('utf-8').rstrip('=')
    
    return code_verifier, code_challenge

# Authorization request includes code_challenge
# Token exchange requires code_verifier
# Authorization server verifies they match

Operational Controls

Configuration hygiene matters. Here's what RFC 9700 mandates:

  • Exact redirect URI matching: No wildcards, no prefix matching, no substring checks
  • State parameter validation: Cryptographically random, verified on callback
  • Short-lived authorization codes: 10 minutes maximum, single-use only
  • Token binding where possible: Sender-constrained tokens via mTLS or DPoP
  • Regular access reviews: Audit OAuth grants quarterly, revoke unused integrations

Third-party OAuth integrations extend your attack surface. Every SaaS application with access to your Google Workspace, Salesforce, or Microsoft 365 tenant is a potential entry point. The Salesloft-Drift breach proved that compromise one hop away is still compromise. Inventory every OAuth application, classify by data sensitivity, and apply the principle of least privilege ruthlessly.

The Bottom Line

OAuth security isn't about checking boxes during implementation. It's about continuous monitoring, strict validation, and assuming tokens will be stolen. Build your defenses accordingly.

Generate Secure Passwords Locally

Creating API keys or service accounts? Generate cryptographically secure passwords with customizable length and character sets—client-side only.

Open Password Generator →
Share this: