{"record":{"id":"1635e6b829f225b7","repo":"google-gemini/gemini-cli","slug":"invalid-oauth-endpoint-url-resolvedurl-get","errorCode":null,"errorMessage":"Invalid OAuth endpoint URL \"${resolvedUrl}\": ${getErrorMessage(e)}","messagePattern":"Invalid OAuth endpoint URL \"(.+?)\": (.+?)","errorType":"exception","errorClass":"OAuthSecurityError","httpStatus":null,"severity":"error","filePath":"packages/core/src/mcp/oauth-utils.ts","lineNumber":81,"sourceCode":"  urlStr: string,\n  options?: OAuthUrlValidationOptions,\n): Promise<string> {\n  let resolvedUrl = urlStr.trim();\n  if (options?.allowRelative && options.baseUri) {\n    try {\n      resolvedUrl = new URL(resolvedUrl, options.baseUri).toString();\n    } catch (e) {\n      throw new OAuthSecurityError(\n        `Failed to resolve relative OAuth URL \"${urlStr}\" against base \"${options.baseUri}\": ${getErrorMessage(e)}`,\n      );\n    }\n  }\n\n  let parsed: URL;\n  try {\n    parsed = new URL(resolvedUrl);\n  } catch (e) {\n    throw new OAuthSecurityError(\n      `Invalid OAuth endpoint URL \"${resolvedUrl}\": ${getErrorMessage(e)}`,\n    );\n  }\n\n  const isHttp = parsed.protocol === 'http:';\n  const isHttps = parsed.protocol === 'https:';\n  if (!isHttp && !isHttps) {\n    throw new OAuthSecurityError(\n      `Invalid OAuth endpoint protocol \"${parsed.protocol}\". Only HTTPS (and HTTP for local development) is supported.`,\n    );\n  }\n\n  const hostname = sanitizeHostname(parsed.hostname);\n  const isLoopback = isLoopbackHost(hostname);\n\n  if (isHttp && (!options?.allowLoopback || !isLoopback)) {\n    throw new OAuthSecurityError(\n      `Insecure HTTP OAuth endpoint \"${resolvedUrl}\" is not allowed. OAuth endpoints must use HTTPS unless connecting to localhost.`,","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/3c311beac2e78336816dd4a123db39743f9fbf85/packages/core/src/mcp/oauth-utils.ts#L63-L99","documentation":"The resolved OAuth endpoint string is not parseable as an absolute URL. After optional relative-resolution, the library runs new URL(resolvedUrl) and throws this OAuthSecurityError if parsing fails. This means the value is not a URL at all (no scheme/host) or contains syntax the WHATWG URL parser rejects.","triggerScenarios":"Passing a bare hostname ('auth.example.com'), a path-only string without allowRelative/baseUri ('/oauth/authorize'), or a string with invalid URL characters to validateOAuthEndpointUrl.","commonSituations":"OAuth metadata discovered from a server returns malformed endpoint values; configuration typos like missing 'https://'; copying endpoint values from docs or .env files that lost the scheme or gained trailing punctuation.","solutions":["Ensure the endpoint string includes a full scheme and host, e.g. 'https://auth.example.com/oauth/authorize'","If the value is intentionally relative, pass { allowRelative: true, baseUri: '<absolute base>' } so it gets resolved first","Check for stray whitespace, quotes, or template-literal artifacts in the configured value (urlStr is trimmed, but embedded characters still break parsing)","Inspect the raw authorization_server/registration_endpoint metadata your server returns and fix it server-side if it is malformed"],"exampleFix":"// before\nawait validateOAuthEndpointUrl('auth.example.com/oauth/authorize');\n\n// after\nawait validateOAuthEndpointUrl('https://auth.example.com/oauth/authorize');","handlingStrategy":"validation","validationCode":"function isParseableAbsoluteUrl(v: string): boolean {\n  try { new URL(v); return true; } catch { return false; }\n}\n\nif (!isParseableAbsoluteUrl(endpoint) && !opts?.allowRelative) {\n  throw new Error(`Config bug: endpoint '${endpoint}' must be an absolute URL`);\n}","typeGuard":"function isValidHttpUrl(v: unknown): v is string {\n  if (typeof v !== 'string') return false;\n  try { const u = new URL(v); return u.protocol === 'http:' || u.protocol === 'https:'; } catch { return false; }\n}","tryCatchPattern":"try {\n  await validateOAuthEndpointUrl(endpoint);\n} catch (e) {\n  if (e instanceof OAuthSecurityError && e.message.startsWith('Invalid OAuth endpoint URL')) {\n    // log the raw endpoint value and its source (env/config/metadata), fix the string\n  }\n  throw e;\n}","preventionTips":["Always configure full https:// URLs for OAuth endpoints","Validate discovered metadata endpoint strings before use","Add a lint/startup check that every URL-typed config value passes new URL()"],"tags":["oauth","url-parsing","validation","mcp"],"backgroundTag":"invalid-url","analyzedSha":"3c311beac2e78336816dd4a123db39743f9fbf85","analyzedAt":"2026-08-27T19:07:12.298Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}