{"record":{"id":"72caf7b81a47950a","repo":"different-ai/openwork","slug":"sign-in-to-your-den-portal-to-install-openwork","errorCode":null,"errorMessage":"Sign in to your Den portal to install OpenWork.","messagePattern":"Sign in to your Den portal to install OpenWork\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/_components/install-screen.tsx","lineNumber":165,"sourceCode":"    apiUrl,\n    requireSignin,\n    logoUrl,\n    iconUrl,\n    desktopVersion,\n    distribution,\n  };\n}\n\nasync function fetchInstallConfig(token: string | null) {\n  const path = token ? `/v1/install-config?token=${encodeURIComponent(token)}` : \"/v1/me/install-config\";\n  const { response, payload } = await requestJson(\n    path,\n    { method: \"GET\" },\n    12000,\n  );\n  if (!response.ok) {\n    if (!token && response.status === 401) {\n      throw new Error(\"Sign in to your Den portal to install OpenWork.\");\n    }\n    throw new Error(getInstallConfigErrorMessage(payload, response.status));\n  }\n  const parsed = parseInstallConfig(payload);\n  if (!parsed) {\n    throw new Error(\"This install link returned incomplete setup details.\");\n  }\n  return parsed;\n}\n\nfunction installHref(config: InstallConfig, platform: InstallPlatform, token: string | null) {\n  return token\n    ? buildInstallDownloadHref(config.apiUrl, platform, token)\n    : buildAuthenticatedInstallDownloadHref(config.apiUrl, platform);\n}\n\ntype StepState = \"complete\" | \"active\" | \"pending\";\n","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/_components/install-screen.tsx#L147-L183","documentation":"fetchInstallConfig in the Den install screen fetches /v1/install-config with an optional install token. If the response is 401 and no token was supplied, it throws \"Sign in to your Den portal to install OpenWork.\" — the server requires an authenticated Den session (or a valid install token) to hand out installer configuration.","triggerScenarios":"Opening the install page with an install link whose token is absent/missing from the URL, causing an unauthenticated GET to /v1/install-config that returns 401.","commonSituations":"User copied the install page URL without the token query parameter; token was stripped by a link sanitizer/chat client; user hit the install screen directly instead of via an admin-generated install link.","solutions":["Sign in to the Den portal, then reopen the install screen so the request carries the session.","Ask the workspace admin for a fresh install link that includes the token and open it as-is (don't trim the query string).","If the link exists, ensure installTokenFromPageUrl is extracting the token correctly before fetchInstallConfig runs."],"exampleFix":"// before\nawait fetchInstallConfig(null)  // 401, no token\n// after\nconst token = installTokenFromPageUrl(installPageUrl);\nawait fetchInstallConfig(token)","handlingStrategy":"type-guard","validationCode":"const token = installTokenFromPageUrl(window.location.href);\nif (!token) {\n  // route the user to Den sign-in instead of calling the API\n  redirectToSignIn();\n}","typeGuard":"function hasInstallToken(t) {\n  return typeof t === \"string\" && t.trim().length > 0;\n}","tryCatchPattern":"try {\n  await fetchInstallConfig(token);\n} catch (err) {\n  if (err.message === \"Sign in to your Den portal to install OpenWork.\") {\n    showSignInPrompt();\n  } else throw err;\n}","preventionTips":["Check for the token query param on the install page before fetching config.","Never share install links through sanitizers that strip query strings.","Generate links via the admin Members page so they include a valid token."],"tags":["auth","http-401","install","den"],"backgroundTag":"unauthorized-401","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}