{"record":{"id":"06405c027d396980","repo":"Budibase/budibase","slug":"authentication-is-required-to-link-chat-identity","errorCode":null,"errorMessage":"Authentication is required to link chat identity","messagePattern":"Authentication is required to link chat identity","errorType":"http","errorClass":"HTTPError","httpStatus":401,"severity":"error","filePath":"packages/server/src/api/controllers/ai/chatIdentityLinks.ts","lineNumber":267,"sourceCode":"  ctx: UserCtx<\n    { confirmationToken?: string },\n    string,\n    { instance: string; token: string }\n  >\n) {\n  const token = resolveToken(ctx.params.token)\n  const session =\n    await sdk.ai.chatIdentityLinks.getChatIdentityLinkSession(token)\n  if (!session) {\n    throw new HTTPError(\"Link token is invalid or has expired\", 400)\n  }\n  assertSessionMatchesInstance({\n    workspaceId: session.workspaceId,\n    instance: ctx.params.instance,\n  })\n\n  if (!ctx.isAuthenticated) {\n    throw new HTTPError(\"Authentication is required to link chat identity\", 401)\n  }\n\n  const currentGlobalUserId = getCurrentGlobalUserId(ctx)\n  if (\n    !session.confirmationToken ||\n    !session.confirmationGlobalUserId ||\n    session.confirmationGlobalUserId !== currentGlobalUserId ||\n    ctx.request.body?.confirmationToken !== session.confirmationToken\n  ) {\n    throw new HTTPError(\"Link confirmation is invalid or has expired\", 400)\n  }\n\n  const consumedSession =\n    await sdk.ai.chatIdentityLinks.consumeChatIdentityLinkSession(token)\n  if (!consumedSession) {\n    throw new HTTPError(\"Link token is invalid or has expired\", 400)\n  }\n  assertSessionMatchesInstance({","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/api/controllers/ai/chatIdentityLinks.ts#L249-L285","documentation":"Confirming a chat identity link attaches the link to the currently signed-in Budibase user, so confirmChatLinkSession requires an authenticated request (ctx.isAuthenticated). The session/workspace checks pass first; only after that is auth enforced, returning HTTP 401 if the caller has no valid session.","triggerScenarios":"Hitting the confirm link route without being logged into the Budibase web app — e.g. opening the confirmation URL in a browser/profile without an active session cookie, after session expiry, or via an API client that sends no credentials.","commonSituations":"User clicks the confirmation link on a different device/browser than where they logged in; session cookie expired between handoff and confirm; corporate browsers blocking third-party cookies on the app domain; calling the endpoint with curl without session auth.","solutions":["Log in to the Budibase instance in the same browser before opening the confirmation link","Re-authenticate if the session expired, then re-open (or re-issue) the confirm link","Open the link on the device/browser where the user is signed in","If testing via API, send valid session credentials with the request"],"exampleFix":"// before\ncurl -X POST https://example.com/api/chat-links/instance1/tok123/confirm\n// after\ncurl -X POST https://example.com/api/chat-links/instance1/tok123/confirm \\\n  -H \"Cookie: <authenticated-session-cookie>\"","handlingStrategy":"try-catch","validationCode":"// client-side check before opening the confirm URL\nif (!document.cookie.includes(\"budibase\")) location.href = \"/login?returnTo=\" + encodeURIComponent(confirmUrl)","typeGuard":null,"tryCatchPattern":"try {\n  await api.confirmLink(instance, token)\n} catch (e) {\n  if (e instanceof HTTPError && e.status === 401) {\n    // redirect the user to login, preserving the confirm URL for retry\n  }\n  throw e\n}","preventionTips":["Log in to the Budibase app in the same browser before confirming","Preserve and redirect back to the confirm URL after login","Ensure cookies are not blocked for the app domain","Send session credentials when calling the endpoint programmatically"],"tags":["auth","http-401","identity-link"],"backgroundTag":"unauthenticated-request","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}