{"record":{"id":"d41696e571863da0","repo":"jackwener/OpenCLI","slug":"linkedin-messaging-api-authentication-failed","errorCode":null,"errorMessage":"LinkedIn messaging API authentication failed: ","messagePattern":"LinkedIn messaging API authentication failed: ","errorType":"error_code","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/inbox.js","lineNumber":198,"sourceCode":"      throw new CommandExecutionError(\n        'LinkedIn did not issue a messaging API request; the inbox may have failed to load.',\n      );\n    }\n\n    const cookies = await page.getCookies({ url: 'https://www.linkedin.com' });\n    const jsession = cookies.find((c) => c.name === 'JSESSIONID')?.value;\n    if (!jsession) {\n      throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn JSESSIONID cookie not found. Please sign in to LinkedIn.');\n    }\n    const csrf = jsession.replace(/^\"|\"$/g, '');\n\n    // Widen the page size to the requested limit where the query supports it.\n    const targetUrl = located.url.replace(/count:\\d+/, 'count:' + limit);\n    const fetched = unwrapEvaluateResult(\n      await page.evaluate(`(${fetchMessagingApi.toString()})(${JSON.stringify(targetUrl)}, ${JSON.stringify(csrf)})`),\n    );\n    if (fetched && fetched.authRequired) {\n      throw new AuthRequiredError(LINKEDIN_DOMAIN, 'LinkedIn messaging API authentication failed: ' + fetched.error);\n    }\n    if (!fetched || fetched.error || !fetched.json) {\n      throw new CommandExecutionError(\n        'LinkedIn messaging API returned an unexpected response: ' + ((fetched && fetched.error) || 'no data'),\n      );\n    }\n\n    let conversations = parseConversations(fetched.json, located.mailboxUrn || '');\n    if (unreadOnly) conversations = conversations.filter((c) => c.unread);\n    if (conversations.length === 0) {\n      if (unreadOnly) return [];\n      throw new EmptyResultError('linkedin inbox', 'No LinkedIn conversations were found in the inbox.');\n    }\n\n    return conversations.slice(0, limit).map((c, index) => ({\n      rank: index + 1,\n      thread_url: threadUrl(c.thread_id),\n      thread_id: c.thread_id,","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/inbox.js#L180-L216","documentation":"The CLI replays the captured messaging API request from the page context with the session's CSRF token. If the fetch response reports authRequired, an AuthRequiredError is thrown with LinkedIn's own error detail appended. This means LinkedIn's API itself rejected the credentials even though the page looked signed in.","triggerScenarios":"fetchMessagingApi(targetUrl, csrf) returns { authRequired: true, error: ... } when called during `linkedin inbox` — e.g. the API responded 401/403 or a login redirect payload.","commonSituations":"JSESSIONID stale relative to the li_at session (partial logout), CSRF token mismatch after cookie rotation, LinkedIn rate-limiting/challenging the account, or the API endpoint requiring a renewed session.","solutions":["Re-authenticate: sign in again in the automated browser profile to refresh JSESSIONID/li_at, then retry.","Confirm the CSRF token derivation matches the current JSESSIONID (quotes stripped) — re-running after a fresh login fixes stale-token cases.","Reduce request frequency / back off if LinkedIn is throttling the account.","Check fetched.error in the message for the exact API complaint (e.g. 403 challenge) and address it (e.g. complete a security challenge manually)."],"exampleFix":"// before\ninbox(); // AuthRequiredError: API authentication failed (stale session)\n\n// after: refresh session, then retry with backoff\nawait refreshLinkedinSession(profile);\nawait retry(inbox, { attempts: 2, retryOn: AuthRequiredError });","handlingStrategy":"retry","validationCode":"// ensure a fresh session and matching CSRF before the API-backed command\nconst cookies = await page.getCookies({ url: 'https://www.linkedin.com' });\nconst jsession = cookies.find((c) => c.name === 'JSESSIONID')?.value;\nif (!jsession || sessionOlderThan(jsessionTimestamp(), MAX_SESSION_AGE)) {\n  await reloginLinkedin(profile);\n}","typeGuard":"const isApiAuthFailure = (e) => e instanceof AuthRequiredError && /messaging API authentication failed/i.test(e?.message || '');","tryCatchPattern":"try {\n  return await linkedinInbox();\n} catch (e) {\n  if (isApiAuthFailure(e)) {\n    await refreshLinkedinSession(profile);\n    return retry(linkedinInbox, { attempts: 2 });\n  }\n  throw e;\n}","preventionTips":["Re-login whenever the raw page and API session could diverge (partial logouts, cookie rotation).","Throttle request rates to avoid LinkedIn API 401/403 throttling responses.","Complete security challenges manually promptly; API calls fail while the account is challenged.","Log fetched.error detail from the message to distinguish CSRF mismatch from account-level blocks."],"tags":["authentication","api","csrf","linkedin"],"backgroundTag":"api-auth-rejected","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}