{"record":{"id":"3738366d6d9fa73a","repo":"medusajs/medusa","slug":"oidc-label-must-use-https-http-is-only-allow","errorCode":null,"errorMessage":"OIDC '${label}' must use https (http is only allowed for localhost outside of production)","messagePattern":"OIDC '(.+?)' must use https \\(http is only allowed for localhost outside of production\\)","errorType":"validation","errorClass":"MedusaError","httpStatus":400,"severity":"error","filePath":"packages/modules/providers/auth-oidc/src/utils/assert-secure-url.ts","lineNumber":27,"sourceCode":"  try {\n    url = new URL(value)\n  } catch (e) {\n    throw new MedusaError(\n      MedusaError.Types.INVALID_DATA,\n      `OIDC '${label}' must be a valid URL`\n    )\n  }\n\n  const isLocalhost =\n    url.hostname === \"localhost\" ||\n    url.hostname === \"127.0.0.1\" ||\n    url.hostname === \"::1\" ||\n    url.hostname === \"[::1]\"\n\n  const allowsHttp = isLocalhost && !isProduction()\n\n  if (url.protocol !== \"https:\" && !(url.protocol === \"http:\" && allowsHttp)) {\n    throw new MedusaError(\n      MedusaError.Types.INVALID_DATA,\n      `OIDC '${label}' must use https (http is only allowed for localhost outside of production)`\n    )\n  }\n}\n","sourceCodeStart":9,"sourceCodeEnd":33,"githubUrl":"https://github.com/medusajs/medusa/blob/5e06e544a296b9033f20f71f11c559f81a0e5739/packages/modules/providers/auth-oidc/src/utils/assert-secure-url.ts#L9-L33","documentation":"assertSecureUrl requires https for both issuer and callback_url. Plain http is tolerated only when the hostname is localhost/127.0.0.1/::1 AND the process is not running in production (NODE_ENV=production); otherwise it throws INVALID_DATA.","triggerScenarios":"Deploying with issuer or callback_url on http:// while NODE_ENV=production; using an http staging host that is not localhost; http callback through a non-localhost docker hostname in prod mode.","commonSituations":"Config built for local dev (http://localhost:8000) promoted to production where the public URL must be https; sitting behind a TLS-terminating proxy but the app constructs the callback from an internal http base URL; NODE_ENV left as production during a docker-compose test using http service names.","solutions":["Use https URLs for issuer and callback_url in production (e.g. put your domain behind a TLS proxy/CDN).","Derive callback_url from the forwarded public origin (e.g. trust X-Forwarded-Proto) instead of the internal request host.","For non-production testing on non-localhost hosts, either add a hosts mapping to localhost or run NODE_ENV != production."],"exampleFix":"// before\noptions: { issuer: \"http://auth.internal:8080\", callback_url: \"http://app.internal:9000/auth/customer/oidc/callback\" } // NODE_ENV=production -> throws\n// after\noptions: { issuer: \"https://auth.example.com\", callback_url: \"https://app.example.com/auth/customer/oidc/callback\" }","handlingStrategy":"validation","validationCode":"const u = new URL(options.issuer)\nconst isLocal = [\"localhost\",\"127.0.0.1\",\"::1\"].includes(u.hostname)\nif (process.env.NODE_ENV === \"production\" && u.protocol !== \"https:\") {\n  throw new Error(\"production OIDC URLs must use https\")\n}","typeGuard":"const isSecureEnoughUrl = (v: string): boolean => { try { const u = new URL(v); return u.protocol === \"https:\" || ([\"localhost\",\"127.0.0.1\",\"::1\"].includes(u.hostname) && process.env.NODE_ENV !== \"production\") } catch { return false } }","tryCatchPattern":"try { assertSecureUrl(value, label) } catch (e) { if (e instanceof MedusaError && /must use https/.test(e.message)) { /* switch to https or non-production localhost */ } throw e }","preventionTips":["Terminate TLS before the app and build public URLs from X-Forwarded-Proto.","Keep separate env files per environment with correct schemes.","Never ship http IdP URLs with NODE_ENV=production."],"tags":["oidc","https","tls","configuration","production"],"backgroundTag":"insecure-url-rejected","analyzedSha":"5e06e544a296b9033f20f71f11c559f81a0e5739","analyzedAt":"2026-08-27T07:24:39.599Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}