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
- Use an https:// endpoint for anything non-loopback (the primary fix)
- For local development, use a loopback hostname (localhost, 127.0.0.1, [::1]) and pass { allowLoopback: true }
- 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
- 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
- Default all OAuth endpoint config to https://; require an explicit opt-in for http
- Reserve http:// for localhost development only
- Provision TLS even in staging (e.g. mkcert or a reverse proxy) so dev mirrors production
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
- OAuth endpoint origin "${parsed.origin}" does not match expe
- Failed to resolve relative OAuth URL "${urlStr}" against bas
- Invalid OAuth endpoint protocol "${parsed.protocol}". Only H
- Loopback OAuth endpoint "${resolvedUrl}" is not allowed for
- OAuth endpoint "${resolvedUrl}" points to private or reserve
AI-assisted analysis of google-gemini/gemini-cli@3c311beac2 (2026-08-27).
Data as JSON: /api/errors/bc085a3c554d8ce0.
Report an issue: GitHub.