jackwener/OpenCLI · error · AuthRequiredError
linkedin.com: LinkedIn li_at cookie missing
Error message
linkedin.com: LinkedIn li_at cookie missing
What it means
verifyLinkedinLearningIdentity checks the Puppeteer page for a non-empty LinkedIn 'li_at' session cookie before probing the Learning API. Without it, LinkedIn Learning endpoints redirect to a login page, so the command throws AuthRequiredError early. This tells the user they must log in to LinkedIn in the automation browser first.
Source
Thrown at clis/linkedin-learning/auth.js:11
import { AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors';
import { registerSiteAuthCommands } from '../_shared/site-auth.js';
async function hasLinkedinSessionCookie(page) {
const cookies = await page.getCookies({ url: 'https://www.linkedin.com' });
return cookies.some(c => c.name === 'li_at' && c.value);
}
async function verifyLinkedinLearningIdentity(page) {
if (!await hasLinkedinSessionCookie(page)) {
throw new AuthRequiredError('linkedin.com', 'LinkedIn li_at cookie missing');
}
await page.goto('https://www.linkedin.com/learning/');
await page.wait(2);
const result = await page.evaluate(`(async () => {
try {
const jsessionRaw = (document.cookie.split('; ').find(c => c.startsWith('JSESSIONID=')) || '').split('=')[1] || '';
const csrf = jsessionRaw.replace(/^"|"$/g, '');
if (!csrf) return { kind: 'auth', detail: 'LinkedIn JSESSIONID missing — csrf token unavailable' };
const res = await fetch('/voyager/api/me', { credentials: 'include', headers: { 'csrf-token': csrf, 'Accept': 'application/json' } });
if (res.status === 401 || res.status === 403) {
return { kind: 'auth', detail: 'LinkedIn /voyager/api/me HTTP ' + res.status };
}
if (!res.ok) return { kind: 'http', httpStatus: res.status };
const d = await res.json();
const mini = d && d.miniProfile;
if (!mini || !mini.publicIdentifier) {
return { kind: 'auth', detail: 'LinkedIn /voyager/api/me 200 but miniProfile missing' };
}View on GitHub (pinned to 49907e53dc)
Solutions
- Run the site's login flow (the registered loginUrl https://www.linkedin.com/login?session_redirect=%2Flearning%2F) and complete LinkedIn login in the automation browser.
- Confirm li_at exists after login: document.cookie or page.getCookies shows li_at with a value.
- If the session expired, log in again to get a fresh li_at cookie.
- Ensure the browser profile used persists cookies between runs.
Example fix
// before
await runCommand('linkedin-learning course <slug>'); // fails: no session
// after
await runCommand('linkedin-learning login'); // complete LinkedIn login in the browser
const identity = await runCommand('linkedin-learning whoami'); Defensive patterns
Strategy: validation
Validate before calling
const cookies = await page.getCookies({ url: 'https://www.linkedin.com' });
const hasLiAt = cookies.some(c => c.name === 'li_at' && c.value);
if (!hasLiAt) {
await startLoginFlow('https://www.linkedin.com/login?session_redirect=%2Flearning%2F');
} Type guard
function hasLiAtCookie(cookies) {
return Array.isArray(cookies) && cookies.some(c => c?.name === 'li_at' && typeof c.value === 'string' && c.value.length > 0);
} Try / catch
try {
const identity = await verifyLinkedinLearningIdentity(page);
} catch (e) {
if (e.name === 'AuthRequiredError' && e.message.includes('li_at')) {
await runInteractiveLogin('linkedin-learning');
return verifyLinkedinLearningIdentity(page);
}
throw e;
} Prevention
- Run the login flow before any Learning command in a fresh profile.
- Use a persistent browser profile so li_at survives across runs.
- Re-login when LinkedIn rotates or invalidates the session.
- Check cookie presence as a quickCheck before long operations.
When it happens
Trigger: Calling any linkedin-learning command (via registerSiteAuthCommands verify flow) when page.getCookies({ url: 'https://www.linkedin.com' }) contains no 'li_at' cookie with a non-empty value.
Common situations: First run of the tool before ever logging in; expired LinkedIn session (li_at rotated/cleared); running with a fresh browser profile or in CI where no cookies exist; user logged out of LinkedIn elsewhere invalidating the session.
Related errors
- Waiting for Ctrip login_uid cookie
- my.hupu.com
- Not logged in — open jimeng.jianying.com in Chrome and sign
- Kimi access_token cookie missing
- linkedin.com: ${result.detail}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/1e71f402c2573c9c.
Report an issue: GitHub.