{"record":{"id":"b8c407fab8b4068b","repo":"BloopAI/vibe-kanban","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"http","errorClass":"ApiError","httpStatus":401,"severity":"error","filePath":"packages/web-core/src/shared/lib/api.ts","lineNumber":1302,"sourceCode":"\n  logout: async (): Promise<void> => {\n    const response = await makeRequest('/api/auth/logout', {\n      method: 'POST',\n    });\n    if (!response.ok) {\n      throw new ApiError(\n        `Logout failed with status ${response.status}`,\n        response.status,\n        response\n      );\n    }\n  },\n\n  /** Returns the current access token for the remote server (auto-refreshes if needed) */\n  getToken: async (): Promise<TokenResponse> => {\n    const response = await makeRequest('/api/auth/token');\n    if (response.status === 401) {\n      throw new ApiError('Unauthorized', 401, response);\n    }\n    return handleApiResponse<TokenResponse>(response);\n  },\n\n  /** Returns the user ID of the currently authenticated user */\n  getCurrentUser: async (): Promise<CurrentUserResponse> => {\n    const response = await makeRequest('/api/auth/user');\n    return handleApiResponse<CurrentUserResponse>(response);\n  },\n};\n\n/**\n * @deprecated Use `tokenManager.getToken()` from\n * `@/shared/lib/auth/tokenManager` instead.\n * This function does not handle 401 responses or token refresh coordination.\n */\nexport async function getCachedToken(): Promise<string | null> {\n  const { tokenManager } = await import('@/shared/lib/auth/tokenManager');","sourceCodeStart":1284,"sourceCodeEnd":1320,"githubUrl":"https://github.com/BloopAI/vibe-kanban/blob/4deb7eca8f381f7cbc1f9d15515a9ab8f8009053/packages/web-core/src/shared/lib/api.ts#L1284-L1320","documentation":"oauthApi.getToken() calls GET /api/auth/token to fetch the current remote-server access token and throws ApiError('Unauthorized', 401) when that endpoint answers 401. This library throws it explicitly (instead of relying on handleApiResponse) so callers can detect an unauthenticated/expired session for the token endpoint specifically. It means the server refused to issue a token because the user has no valid session or refresh credentials.","triggerScenarios":"The user's session cookie is missing/expired when /api/auth/token is called; the refresh token stored server-side is revoked or expired; the request is made before any login has occurred; server-side session was invalidated (logout elsewhere, server restart clearing sessions).","commonSituations":"Remote deployments where the browser session cookie has expired after idle timeout; calling token-gated features without completing OAuth/local login; server restarted and wiped in-memory session store; user token revoked after password change.","solutions":["Check the response status and redirect the user to the login flow (e.g. oauthApi.handoffInit or localLogin) instead of retrying.","Call oauthApi.status() or authMethods() first to confirm whether auth is required and a session exists.","Clear stale client auth state and force a fresh login, then retry getToken().","Verify the backend session store (cookies/refresh tokens) is persistent and not being cleared on restart."],"exampleFix":"// before\nconst token = await oauthApi.getToken();\n// after\ntry {\n  const token = await oauthApi.getToken();\n} catch (e) {\n  if (e instanceof ApiError && e.status === 401) {\n    window.location.assign('/login?returnTo=' + encodeURIComponent(window.location.pathname));\n    return;\n  }\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":"const status = await oauthApi.status();\nif (!status.authenticated) redirectToLogin();","typeGuard":"function isAuthError(e: unknown): e is ApiError {\n  return e instanceof ApiError && e.status === 401;\n}","tryCatchPattern":"try {\n  const token = await oauthApi.getToken();\n} catch (e) {\n  if (isAuthError(e)) { redirectToLogin(); return; }\n  throw e;\n}","preventionTips":["Route all token access through tokenManager.getToken() which handles refresh coordination","Call oauthApi.status() on app boot to detect session state early","Redirect to login on any 401 instead of retrying","Keep server session/refresh-token store persistent across restarts"],"tags":["auth","http-401","api"],"backgroundTag":"http-401-unauthorized","analyzedSha":"4deb7eca8f381f7cbc1f9d15515a9ab8f8009053","analyzedAt":"2026-08-29T09:24:13.446Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}