{"record":{"id":"bfa40bd633eeb631","repo":"jackwener/OpenCLI","slug":"12306-tk-auth-cookie-missing","errorCode":null,"errorMessage":"12306 tk auth cookie missing","messagePattern":"12306 tk auth cookie missing","errorType":"exception","errorClass":"AuthRequiredError","httpStatus":null,"severity":"error","filePath":"clis/12306/auth.js","lineNumber":11,"sourceCode":"import { AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors';\nimport { registerSiteAuthCommands } from '../_shared/site-auth.js';\n\nasync function has12306SessionCookie(page) {\n  const cookies = await page.getCookies({ url: 'https://kyfw.12306.cn' });\n  return cookies.some(c => c.name === 'tk' && c.value);\n}\n\nasync function verify12306Identity(page) {\n  if (!await has12306SessionCookie(page)) {\n    throw new AuthRequiredError('12306.cn', '12306 tk auth cookie missing');\n  }\n  await page.goto('https://kyfw.12306.cn/otn/view/index.html');\n  await page.wait(2);\n  const probe = await page.evaluate(`(async () => {\n    try {\n      const r = await fetch('/otn/index/initMy12306Api', {\n        method: 'POST',\n        credentials: 'include',\n        headers: { 'X-Requested-With': 'XMLHttpRequest' },\n      });\n      if (/login\\\\.html/.test(r.url)) {\n        return { kind: 'auth', detail: '12306 initMy12306Api redirected to login' };\n      }\n      const t = await r.text();\n      let d = null;\n      try { d = JSON.parse(t); } catch {}\n      if (!d || d.status === false || /未登录|登录超时|NotLogin/i.test(t)) {\n        return { kind: 'auth', detail: '12306 initMy12306Api returned NotLogin' };","sourceCodeStart":1,"sourceCodeEnd":29,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/12306/auth.js#L1-L29","documentation":"AuthRequiredError thrown when `twitter bookmark-folders` (list command) finds no `ct0` cookie for https://x.com. The command needs the CSRF token from an authenticated session to call the bookmark-folders GraphQL endpoint, so it fails fast before making any request.","triggerScenarios":"Running the listing command with a browser session that has never logged into x.com; cookies cleared; wrong browser profile attached; incognito/non-persistent context.","commonSituations":"CI or scheduled jobs using a fresh browser context; switching machines or profiles; x.com logged the session out due to suspicious activity, purging cookies.","solutions":["Log into x.com interactively in the CLI's browser session and retry","Ensure the CLI uses the persistent profile containing your x.com login","After login, verify the ct0 cookie exists for x.com (devtools → Application → Cookies)","Keep the session alive; avoid cookie-clearing extensions or scripts"],"exampleFix":"// before\nopencli twitter bookmark-folders   # not logged in\n// after\nopencli browser open https://x.com/login   # complete login in this profile\nopencli twitter bookmark-folders","handlingStrategy":"try-catch","validationCode":"const cookies = await page.getCookies({ url: 'https://x.com' });\nif (!cookies.some(c => c.name === 'ct0')) throw new Error('Not logged into x.com');","typeGuard":"function hasCt0(cookies) { return Array.isArray(cookies) && cookies.some(c => c && c.name === 'ct0' && typeof c.value === 'string' && c.value.length > 0); }","tryCatchPattern":"try {\n  const folders = await opencli('twitter bookmark-folders');\n} catch (e) {\n  if (/no ct0 cookie/.test(e.message)) {\n    await opencli('browser open', 'https://x.com/login');\n    // retry after login\n  }\n}","preventionTips":["Bootstrap login before automated runs","Persist the browser profile","Check ct0 cookie presence in preflight checks","Re-login after x.com forces sign-out"],"tags":["authentication","twitter","cookies","csrf"],"backgroundTag":"missing-auth-cookie","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}