{"record":{"id":"d548ab9862a97669","repo":"can1357/oh-my-pi","slug":"gitlab-redirect-uri-loopback-callbacks-must-use-ht","errorCode":null,"errorMessage":"GITLAB_REDIRECT_URI loopback callbacks must use http://, got: ${raw}","messagePattern":"GITLAB_REDIRECT_URI loopback callbacks must use http://, got: (.+?)","errorType":"exception","errorClass":"AIError.OAuthError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/registry/oauth/gitlab-duo.ts","lineNumber":77,"sourceCode":"\tlet parsed: URL;\n\ttry {\n\t\tparsed = new URL(raw);\n\t} catch {\n\t\tthrow new AIError.OAuthError(`Invalid GITLAB_REDIRECT_URI: ${raw}`, {\n\t\t\tkind: \"configuration\",\n\t\t\tprovider: \"gitlab-duo\",\n\t\t});\n\t}\n\tif (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n\t\tthrow new AIError.OAuthError(`GITLAB_REDIRECT_URI must use http:// or https://, got: ${raw}`, {\n\t\t\tkind: \"configuration\",\n\t\t\tprovider: \"gitlab-duo\",\n\t\t});\n\t}\n\n\tconst isLoopback = parsed.hostname === \"localhost\" || parsed.hostname === \"127.0.0.1\" || parsed.hostname === \"[::1]\";\n\tif (isLoopback && parsed.protocol !== \"http:\") {\n\t\tthrow new AIError.OAuthError(`GITLAB_REDIRECT_URI loopback callbacks must use http://, got: ${raw}`, {\n\t\t\tkind: \"configuration\",\n\t\t\tprovider: \"gitlab-duo\",\n\t\t});\n\t}\n\n\tconst port = parsed.port ? Number.parseInt(parsed.port, 10) : parsed.protocol === \"https:\" ? 443 : 80;\n\n\treturn {\n\t\tpreferredPort: isLoopback ? port : 0,\n\t\tcallbackPath: parsed.pathname || DEFAULT_CALLBACK_PATH,\n\t\tcallbackHostname: isLoopback ? parsed.hostname : DEFAULT_CALLBACK_HOSTNAME,\n\t\tredirectUri: raw,\n\t};\n}\n\nfunction mapTokenResponse(payload: {\n\taccess_token?: string;\n\trefresh_token?: string;","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/registry/oauth/gitlab-duo.ts#L59-L95","documentation":"When GITLAB_REDIRECT_URI points at a loopback host (localhost, 127.0.0.1, [::1]) the local callback server is plaintext HTTP only, so HTTPS loopback URIs are rejected with this configuration OAuthError. Loopback callbacks must use http://; https:// is only accepted for non-loopback (remote) redirect URIs.","triggerScenarios":"GITLAB_REDIRECT_URI like 'https://localhost:8080/callback', 'https://127.0.0.1/callback', or 'https://[::1]:9090/callback' — a URL that parses, uses an allowed scheme, but combines a loopback hostname with https:.","commonSituations":"Developers assuming OAuth redirect URIs must be HTTPS everywhere and registering 'https://localhost/...' on their GitLab app; copying examples from web-app OAuth setups; IDE auto-completion suggesting https for localhost.","solutions":["Change the scheme of GITLAB_REDIRECT_URI from https:// to http:// for loopback hosts, e.g. http://localhost:8080/callback.","Update the redirect URI registered on your GitLab OAuth application to the same http:// loopback value (GitLab does not require TLS for loopback).","If you genuinely need HTTPS, use a non-loopback hostname (a real domain with TLS termination).","Unset GITLAB_REDIRECT_URI to use the default http://localhost:8080/callback flow."],"exampleFix":"// before (.env)\nGITLAB_REDIRECT_URI=https://localhost:8080/callback\n\n// after (.env)\nGITLAB_REDIRECT_URI=http://localhost:8080/callback","handlingStrategy":"validation","validationCode":"const raw = process.env.GITLAB_REDIRECT_URI?.trim();\nif (raw) {\n  const u = new URL(raw);\n  const loopback = [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(u.hostname);\n  if (loopback && u.protocol !== \"http:\") {\n    throw new Error(`loopback GITLAB_REDIRECT_URI must be http://, got: ${raw}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await loginGitLabDuo(callbacks);\n} catch (err) {\n  if (err?.kind === \"configuration\" && String(err.message).includes(\"loopback callbacks must use http://\")) {\n    process.env.GITLAB_REDIRECT_URI = process.env.GITLAB_REDIRECT_URI!.replace(\"https://\", \"http://\");\n    await loginGitLabDuo(callbacks);\n  } else {\n    throw err;\n  }\n}","preventionTips":["Remember: loopback redirect URIs must be http:// — TLS is only for real (non-loopback) domains.","Update the GitLab OAuth app registration to the http:// loopback URI, not https://localhost.","If HTTPS is a hard requirement, use a public hostname with TLS instead of localhost."],"tags":["oauth","gitlab","configuration","env-var","loopback"],"backgroundTag":"invalid-redirect-uri","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}