{"record":{"id":"89b80c2e92ec5cc0","repo":"gethomepage/homepage","slug":"homepage-external-url-or-nextauth-url-must-be-an-89b80c","errorCode":null,"errorMessage":"HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) must be an absolute HTTP(S) URL without credentials, query, or fragment.","messagePattern":"HOMEPAGE_EXTERNAL_URL \\(or NEXTAUTH_URL\\) must be an absolute HTTP\\(S\\) URL without credentials, query, or fragment\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"src/pages/api/auth/[...nextauth].js","lineNumber":54,"sourceCode":"if (authEnabled) {\n  if (!process.env.NEXTAUTH_URL) {\n    throw new Error(\"Homepage auth is enabled but HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) is missing.\");\n  }\n\n  try {\n    parsedAuthUrl = new URL(process.env.NEXTAUTH_URL);\n  } catch {\n    throw new Error(\"HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) must be an absolute HTTP(S) URL.\");\n  }\n\n  if (\n    ![\"http:\", \"https:\"].includes(parsedAuthUrl.protocol) ||\n    parsedAuthUrl.username ||\n    parsedAuthUrl.password ||\n    parsedAuthUrl.search ||\n    parsedAuthUrl.hash\n  ) {\n    throw new Error(\n      \"HOMEPAGE_EXTERNAL_URL (or NEXTAUTH_URL) must be an absolute HTTP(S) URL without credentials, query, or fragment.\",\n    );\n  }\n\n  if (hasOidcConfig) {\n    if (!process.env.NEXTAUTH_SECRET) {\n      throw new Error(\"OIDC auth is enabled but required settings are missing.\");\n    }\n  } else if (hasAnyOidcConfig) {\n    throw new Error(\"OIDC auth is enabled but required settings are missing.\");\n  } else if (!homepageAuthPassword || !process.env.NEXTAUTH_SECRET) {\n    throw new Error(\"Password auth is enabled but required settings are missing.\");\n  }\n\n  if (process.env.NEXTAUTH_SECRET.length < MIN_AUTH_SECRET_LENGTH) {\n    throw new Error(\n      `HOMEPAGE_AUTH_SECRET (or NEXTAUTH_SECRET) must be at least ${MIN_AUTH_SECRET_LENGTH} characters. Generate one with: openssl rand -base64 32`,\n    );","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/gethomepage/homepage/blob/b6dca1ae033e613d8e692f9a161a3cc53a5a2857/src/pages/api/auth/[...nextauth].js#L36-L72","documentation":"Thrown when the URL parses successfully but is rejected by strict shape rules: must be http/https, must not carry userinfo (user:pass@), query string, or fragment. Homepage enforces a clean origin-style URL because anything else breaks NextAuth callback/redirect logic and can leak credentials.","triggerScenarios":"NEXTAUTH_URL parses but parsedUrl.protocol is not 'http:'/'https:', OR parsedUrl.username/password/search/hash is non-empty. Examples: 'https://home.example.com/?x=1', 'https://u:p@home.example.com', 'https://home.example.com#section', 'ftp://home.example.com'.","commonSituations":"Operator appended a tracking query param or path fragment; reused a connection string that embeds basic-auth credentials; set an ws:// or ftp:// scheme by mistake; pasted a deep link instead of the site origin.","solutions":["Strip any query string and fragment — use only the origin (scheme + host + optional port).","Remove any embedded user:pass@ credentials from the URL.","Ensure the scheme is exactly http or https.","If you need a non-standard port, include it on the host (https://home.example.com:8443) but nothing else."],"exampleFix":"// before\nHOMEPAGE_EXTERNAL_URL=https://home.example.com/?next=/login#top\n\n// after\nHOMEPAGE_EXTERNAL_URL=https://home.example.com","handlingStrategy":"validation","validationCode":"function assertOriginUrl(raw) {\n  const u = new URL(raw); // throws if invalid (see error 1)\n  if (!['http:', 'https:'].includes(u.protocol)) throw new Error('scheme must be http or https');\n  if (u.username || u.password) throw new Error('URL must not contain credentials');\n  if (u.search || u.hash) throw new Error('URL must not contain query or fragment');\n  return u;\n}","typeGuard":"function isCleanOriginUrl(v) {\n  if (!isValidAbsoluteUrl(v)) return false;\n  const u = new URL(v);\n  return ['http:', 'https:'].includes(u.protocol)\n    && !u.username && !u.password && !u.search && !u.hash;\n}","tryCatchPattern":null,"preventionTips":["Standardize on the origin only (scheme://host[:port]) in config.","Reject deep links at the config layer so they never reach auth.","Add a CI lint that checks HOMEPAGE_EXTERNAL_URL against ^https?://[^/?#]+$.","Never embed basic-auth credentials in the URL."],"tags":["auth","configuration","env","validation","url"],"backgroundTag":null,"analyzedSha":"b6dca1ae033e613d8e692f9a161a3cc53a5a2857","analyzedAt":"2026-08-13T04:48:44.121Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}