google-gemini/gemini-cli · error · OAuthSecurityError

Insecure HTTP OAuth endpoint "${resolvedUrl}" is not allowed

Error message

Insecure HTTP OAuth endpoint "${resolvedUrl}" is not allowed. OAuth endpoints must use HTTPS unless connecting to localhost.

What it means

The endpoint uses plain http:// but the host is not a loopback address (or allowLoopback was not requested). OAuth traffic over unencrypted HTTP leaks credentials and tokens, so the library restricts HTTP to loopback development scenarios (localhost, 127.0.0.1, ::1).

Source

Thrown at packages/core/src/mcp/oauth-utils.ts:98

  } catch (e) {
    throw new OAuthSecurityError(
      `Invalid OAuth endpoint URL "${resolvedUrl}": ${getErrorMessage(e)}`,
    );
  }

  const isHttp = parsed.protocol === 'http:';
  const isHttps = parsed.protocol === 'https:';
  if (!isHttp && !isHttps) {
    throw new OAuthSecurityError(
      `Invalid OAuth endpoint protocol "${parsed.protocol}". Only HTTPS (and HTTP for local development) is supported.`,
    );
  }

  const hostname = sanitizeHostname(parsed.hostname);
  const isLoopback = isLoopbackHost(hostname);

  if (isHttp && (!options?.allowLoopback || !isLoopback)) {
    throw new OAuthSecurityError(
      `Insecure HTTP OAuth endpoint "${resolvedUrl}" is not allowed. OAuth endpoints must use HTTPS unless connecting to localhost.`,
    );
  }

  if (options?.expectedOrigin) {
    let expected: string;
    try {
      expected = new URL(options.expectedOrigin).origin;
    } catch {
      throw new OAuthSecurityError(
        `Invalid expected origin "${options.expectedOrigin}".`,
      );
    }
    if (parsed.origin !== expected) {
      throw new OAuthSecurityError(
        `OAuth endpoint origin "${parsed.origin}" does not match expected origin "${expected}".`,
      );
    }

View on GitHub (pinned to 3c311beac2)

Solutions

  1. Use an https:// endpoint for anything non-loopback (the primary fix)
  2. For local development, use a loopback hostname (localhost, 127.0.0.1, [::1]) and pass { allowLoopback: true }
  3. If the service is only reachable over HTTP on the LAN (e.g. Docker), tunnel it to localhost (e.g. ssh -L) or add TLS via a local reverse proxy
  4. Check environment-specific config to ensure production overrides don't leave http:// defaults

Example fix

// before
await validateOAuthEndpointUrl('http://auth.example.com/authorize');

// after
await validateOAuthEndpointUrl('https://auth.example.com/authorize');
// or, for local dev:
await validateOAuthEndpointUrl('http://localhost:3000/authorize', { allowLoopback: true });
Defensive patterns

Strategy: validation

Validate before calling

function isSecureOrLoopbackHttp(v: string): boolean {
  try {
    const u = new URL(v);
    if (u.protocol === 'https:') return true;
    if (u.protocol !== 'http:') return false;
    return ['localhost', '127.0.0.1', '[::1]'].includes(u.hostname) || /^127\./.test(u.hostname);
  } catch { return false; }
}

if (process.env.NODE_ENV === 'production' && !endpoint.startsWith('https://')) {
  throw new Error('OAuth endpoints must use HTTPS in production');
}

Type guard

function isHttpsUrl(v: string): v is `https://${string}` {
  return v.startsWith('https://');
}

Try / catch

try {
  await validateOAuthEndpointUrl(endpoint, { allowLoopback: isLocalDev });
} catch (e) {
  if (e instanceof OAuthSecurityError && e.message.includes('Insecure HTTP OAuth endpoint')) {
    // switch to https, or use a loopback host with allowLoopback: true for local dev
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing an http:// URL with a non-loopback host, e.g. 'http://auth.example.com/token'; or an http:// loopback URL without { allowLoopback: true } in options.

Common situations: Local development against a server on the LAN or a docker host accessed by IP (e.g. http://192.168.x.x) instead of localhost; staging environments without TLS certificates; env-var configurations defaulting to http in production.

Related errors


AI-assisted analysis of google-gemini/gemini-cli@3c311beac2 (2026-08-27). Data as JSON: /api/errors/bc085a3c554d8ce0. Report an issue: GitHub.