BloopAI/vibe-kanban · error · ApiError
Unauthorized
Error message
Unauthorized
What it means
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.
Source
Thrown at packages/web-core/src/shared/lib/api.ts:1302
logout: async (): Promise<void> => {
const response = await makeRequest('/api/auth/logout', {
method: 'POST',
});
if (!response.ok) {
throw new ApiError(
`Logout failed with status ${response.status}`,
response.status,
response
);
}
},
/** Returns the current access token for the remote server (auto-refreshes if needed) */
getToken: async (): Promise<TokenResponse> => {
const response = await makeRequest('/api/auth/token');
if (response.status === 401) {
throw new ApiError('Unauthorized', 401, response);
}
return handleApiResponse<TokenResponse>(response);
},
/** Returns the user ID of the currently authenticated user */
getCurrentUser: async (): Promise<CurrentUserResponse> => {
const response = await makeRequest('/api/auth/user');
return handleApiResponse<CurrentUserResponse>(response);
},
};
/**
* @deprecated Use `tokenManager.getToken()` from
* `@/shared/lib/auth/tokenManager` instead.
* This function does not handle 401 responses or token refresh coordination.
*/
export async function getCachedToken(): Promise<string | null> {
const { tokenManager } = await import('@/shared/lib/auth/tokenManager');View on GitHub (pinned to 4deb7eca8f)
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.
Example fix
// before
const token = await oauthApi.getToken();
// after
try {
const token = await oauthApi.getToken();
} catch (e) {
if (e instanceof ApiError && e.status === 401) {
window.location.assign('/login?returnTo=' + encodeURIComponent(window.location.pathname));
return;
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
const status = await oauthApi.status(); if (!status.authenticated) redirectToLogin();
Type guard
function isAuthError(e: unknown): e is ApiError {
return e instanceof ApiError && e.status === 401;
} Try / catch
try {
const token = await oauthApi.getToken();
} catch (e) {
if (isAuthError(e)) { redirectToLogin(); return; }
throw e;
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Failed to accept invitation (${res.status})
- Failed to list organizations (${res.status})
- Failed to fetch identity (${res.status})
- Session expired. Please log in again.
- Session expired. Please log in again.
AI-assisted analysis of BloopAI/vibe-kanban@4deb7eca8f (2026-08-29).
Data as JSON: /api/errors/b8c407fab8b4068b.
Report an issue: GitHub.