{"record":{"id":"40ae54b10e20a50d","repo":"bytedance/deer-flow","slug":"invalid-token","errorCode":null,"errorMessage":"Invalid token","messagePattern":"Invalid token","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"backend/app/gateway/langgraph_auth.py","lineNumber":85,"sourceCode":"    Also enforces CSRF on state-changing methods.\n    \"\"\"\n    # CSRF check before authentication so forged cross-site requests\n    # are rejected early, even if the cookie carries a valid JWT.\n    _check_csrf(request)\n\n    if is_auth_disabled():\n        return AUTH_DISABLED_USER_ID\n\n    token = request.cookies.get(\"access_token\")\n    if not token:\n        raise Auth.exceptions.HTTPException(\n            status_code=401,\n            detail=\"Not authenticated\",\n        )\n\n    payload = decode_token(token)\n    if isinstance(payload, TokenError):\n        raise Auth.exceptions.HTTPException(\n            status_code=401,\n            detail=\"Invalid token\",\n        )\n\n    user = await get_local_provider().get_user(payload.sub)\n    if user is None:\n        raise Auth.exceptions.HTTPException(\n            status_code=401,\n            detail=\"User not found\",\n        )\n    if user.token_version != payload.ver:\n        raise Auth.exceptions.HTTPException(\n            status_code=401,\n            detail=\"Token revoked (password changed)\",\n        )\n\n    return payload.sub\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/langgraph_auth.py#L67-L103","documentation":"The `access_token` cookie was present but `decode_token` returned a `TokenError`, meaning the JWT failed decode/validation (bad signature, malformed, or expired). The handler immediately raises HTTP 401 with detail 'Invalid token'. It is distinct from a missing cookie (120) and from a revoked-but-valid token (123).","triggerScenarios":"Presenting an expired JWT cookie; a token signed with a different/rotated secret (server secret changed or multi-instance mismatch); a truncated or tampered cookie value; clock skew pushing the expiry check over the edge.","commonSituations":"JWT secret rotated during redeploy while browsers held old cookies; AUTH_SECRET env var differing between Gateway replicas; long-lived browser sessions after token TTL elapsed with no refresh path; manually editing or re-serializing the cookie.","solutions":["Re-login to mint a fresh token cookie","If tokens expire immediately, verify the token TTL and server clock (NTP) are sane","If all clients fail after a deploy, check whether the signing secret changed and either restore it or force re-login for all users","Ensure every Gateway replica/instance shares the same signing secret"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await call();\n} catch (e) {\n  if (e.status === 401 && /Invalid token/.test(e.detail)) {\n    await login();          // mint a fresh cookie\n    return await call();    // single retry\n  }\n  throw e;\n}","preventionTips":["Refresh/re-login proactively when the token nears its TTL instead of waiting for 401s","Keep the JWT signing secret identical across replicas and redeploys","Distinguish this 401 (bad token) from the no-cookie 401 — only the former implies secret/expiry drift"],"tags":["auth","http-401","jwt","token-expiry"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}