highAuthentication

Insecure OAuth Configuration

What Is This Vulnerability?

Insecure OAuth configuration refers to misimplemented OAuth 2.0 flows that expose tokens, allow authorization code interception, or permit open redirects. Common mistakes include using the implicit flow for server-side apps, not validating the state parameter, accepting wildcard redirect URIs, and storing tokens insecurely in localStorage.

Why It Happens

OAuth 2.0 has multiple grant types and many security-critical parameters. Developers may choose the wrong flow for their application type, skip the state parameter for CSRF protection, configure overly broad redirect URI patterns, or store tokens in browser-accessible storage without understanding the risks.

Example Code

Vulnerableroutes/oauth.ts
app.get("/auth/callback", async (req, res) => {
  const { code } = req.query;
  // No state parameter validation
  const tokenResponse = await fetch("https://oauth.provider.com/token", {
    method: "POST",
    body: new URLSearchParams({
      grant_type: "authorization_code",
      code: code as string,
      client_id: process.env.OAUTH_CLIENT_ID!,
      client_secret: process.env.OAUTH_CLIENT_SECRET!,
      redirect_uri: "https://example.com/auth/callback",
    }),
  });
  const tokens = await tokenResponse.json();
  // Token stored in localStorage via client
  res.json(tokens);
});
Fixedroutes/oauth.ts
app.get("/auth/callback", async (req, res) => {
  const { code, state } = req.query;

  if (!state || state !== req.session.oauthState) {
    return res.status(403).send("Invalid state parameter");
  }
  delete req.session.oauthState;

  const tokenResponse = await fetch("https://oauth.provider.com/token", {
    method: "POST",
    body: new URLSearchParams({
      grant_type: "authorization_code",
      code: code as string,
      client_id: process.env.OAUTH_CLIENT_ID!,
      client_secret: process.env.OAUTH_CLIENT_SECRET!,
      redirect_uri: "https://example.com/auth/callback",
    }),
  });
  const tokens = await tokenResponse.json();

  req.session.accessToken = tokens.access_token;
  res.redirect("/dashboard");
});

How Hackers Exploit It

Without state parameter validation, attackers perform CSRF attacks by tricking users into completing an OAuth flow that links the attacker's account. With overly broad redirect URIs, attackers redirect the authorization code to their own server. If tokens are stored in localStorage, any XSS vulnerability in the application gives the attacker full access to the user's OAuth tokens.

How to Fix It

Always validate the state parameter to prevent CSRF during OAuth flows. Use the authorization code flow with PKCE instead of the implicit flow. Register exact redirect URIs without wildcards. Store tokens in server-side sessions or HttpOnly cookies, never in localStorage. Validate the id_token signature and claims when using OpenID Connect.

Frequently Asked Questions

Why should I not store OAuth tokens in localStorage?
localStorage is accessible to any JavaScript running on the page. If your application has an XSS vulnerability, an attacker can read the token and use it from their own machine. Store tokens in HttpOnly cookies or server-side sessions, where JavaScript cannot access them.
What is PKCE and when should I use it?
PKCE (Proof Key for Code Exchange) adds a cryptographic challenge to the authorization code flow. It prevents authorization code interception attacks, even if the attacker can observe the redirect. Use PKCE for all public clients (SPAs, mobile apps) and it is recommended for confidential clients as well.
What does the OAuth state parameter protect against?
The state parameter prevents CSRF attacks on the OAuth callback. Without it, an attacker can initiate an OAuth flow with their own account and trick the victim into completing it, linking the attacker's external account to the victim's local account.

Related Security Topics

Check Your Code for This Vulnerability

Run a free scan to check if your site is affected by insecure oauth configuration.