makeplane/plane · critical · AppError

AUTH_MISSING_CREDENTIALS

AUTH_MISSING_CREDENTIALS

Error message

Credentials not provided

What it means

In the Live (Hocuspocus) WebSocket authentication hook, after attempting to read a cookie from request parameters and falling back to request headers, the code requires both a cookie and a userId. If neither resolves, it raises an AppError with code AUTH_MISSING_CREDENTIALS and aborts the connection. This is the gatekeeper for the collaborative editing socket.

Source

Thrown at apps/live/src/lib/auth.ts:57

  // the cookies are not passed in the request headers)
  try {
    const parsedToken = JSON.parse(token) as TUserDetails;
    userId = parsedToken.id;
    cookie = parsedToken.cookie;
  } catch (error) {
    const appError = new AppError(error, {
      context: { operation: "onAuthenticate" },
    });
    logger.error("Token parsing failed, using request headers", appError);
  } finally {
    // If cookie is still not found, fallback to request headers
    if (!cookie) {
      cookie = requestHeaders.cookie?.toString();
    }
  }

  if (!cookie || !userId) {
    const appError = new AppError("Credentials not provided", { code: "AUTH_MISSING_CREDENTIALS" });
    logger.error("Credentials not provided", appError);
    throw appError;
  }

  // set cookie in context, so it can be used throughout the ws connection
  context.cookie = cookie ?? requestParameters.get("cookie") ?? "";
  context.documentType = requestParameters.get("documentType")?.toString() as TDocumentTypes;
  context.projectId = requestParameters.get("projectId");
  context.userId = userId;
  context.workspaceSlug = requestParameters.get("workspaceSlug");

  return await handleAuthentication({
    cookie: context.cookie,
    userId: context.userId,
  });
};

export const handleAuthentication = async ({ cookie, userId }: { cookie: string; userId: string }) => {

View on GitHub (pinned to 1c8a60f858)

Solutions

  1. Ensure the browser has an authenticated session cookie before opening the Live socket (log in first).
  2. If behind a proxy, verify the Cookie header is forwarded to the WS handshake.
  3. Check logs for the preceding 'Token parsing failed' warning — a present cookie with empty userId usually means token decode failed.
  4. Confirm SameSite/Secure cookie attributes allow the WS origin.

Example fix

// before
new HocuspocusProvider({ url, name: docName });

// after
if (!document.cookie.includes('session')) {
  await redirectToLogin();
}
new HocuspocusProvider({ url, name: docName });
Defensive patterns

Strategy: validation

Validate before calling

function hasSessionCookie(): boolean { return /session/i.test(document.cookie); }
if (!hasSessionCookie()) { await redirectToLogin(); }

Try / catch

// at the WS provider onError/onAuthenticationFailed
provider.on('authenticationFailed', () => { redirectToLogin(); });

Prevention

When it happens

Trigger: Connecting to the Live WS endpoint without a session cookie (anonymous), with an expired/invalid session that yields no userId, or from a client that sends neither cookie param nor Cookie header.

Common situations: Cookie blocked by SameSite/Secure cross-origin; dev environment without a logged-in session; proxy stripping the Cookie header; token parsing silently failed so userId is empty even though a cookie was present.

Related errors


AI-assisted analysis of makeplane/plane@1c8a60f858 (2026-08-12). Data as JSON: /api/errors/2cb7f3f09b385b53. Report an issue: GitHub.