{"record":{"id":"1b01b5edb367043f","repo":"Significant-Gravitas/AutoGPT","slug":"telegram-login-data-failed-verification","errorCode":null,"errorMessage":"Telegram login data failed verification.","messagePattern":"Telegram login data failed verification\\.","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"autogpt_platform/backend/backend/api/features/platform_linking/routes.py","lineNumber":60,"sourceCode":"    Path(max_length=64, pattern=r\"^[A-Za-z0-9_-]+$\"),\n]\n\n\nclass ConfirmLinkRequest(BaseModel):\n    \"\"\"Optional confirm payload. ``telegram_auth`` carries the signed identity\n    Telegram appends when the user reached this page via a login_url button —\n    when present it must verify, and the link token must belong to that same\n    Telegram user.\"\"\"\n\n    telegram_auth: dict[str, str] | None = Field(default=None)\n\n\ndef _verified_platform_user(body: ConfirmLinkRequest | None) -> str | None:\n    if body is None or not body.telegram_auth:\n        return None\n    verified = verify_login(body.telegram_auth, telegram_config.get_bot_token())\n    if verified is None:\n        raise HTTPException(\n            status_code=403, detail=\"Telegram login data failed verification.\"\n        )\n    return verified\n\n\ndef _translate(exc: Exception) -> HTTPException:\n    if isinstance(exc, NotFoundError):\n        return HTTPException(status_code=404, detail=str(exc))\n    if isinstance(exc, NotAuthorizedError):\n        return HTTPException(status_code=403, detail=str(exc))\n    if isinstance(exc, LinkAlreadyExistsError):\n        return HTTPException(status_code=409, detail=str(exc))\n    if isinstance(exc, LinkTokenExpiredError):\n        return HTTPException(status_code=410, detail=str(exc))\n    if isinstance(exc, LinkFlowMismatchError):\n        return HTTPException(status_code=400, detail=str(exc))\n    return HTTPException(status_code=500, detail=\"Internal error.\")\n","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/Significant-Gravitas/AutoGPT/blob/9c8bb5550f446ba5d3046b78896578742495b3cf/autogpt_platform/backend/backend/api/features/platform_linking/routes.py#L42-L78","documentation":"Raised by the platform-linking confirm route's _verified_platform_user helper when Telegram login data is present on the request but fails cryptographic verification against the bot token (verify_login returns None). It's a 403: the supplied Telegram authentication payload is not trustworthy for that bot.","triggerScenarios":"POSTing a confirm-link request whose telegram_auth dict was tampered with, built with the wrong bot's data, signed with an outdated hash scheme, or whose auth_date is outside the allowed window; also when the backend's telegram_config bot token doesn't match the bot that produced the widget data.","commonSituations":"Frontend forwarding stale Telegram widget data (old auth_date) captured hours earlier; backend configured with a different TELEGRAM_BOT_TOKEN than the bot used at login; clock skew between servers; manually crafted requests in tests without valid hashes.","solutions":["Regenerate the Telegram login data (re-trigger the Telegram login widget) so the hash and auth_date are fresh, then retry immediately.","Verify TELEGRAM_BOT_TOKEN on the backend matches the bot that issued the login payload.","Check server clocks — auth_date freshness checks fail with significant skew.","For tests, construct the hash correctly with HMAC-SHA256 over the data-check-string using the bot token."],"exampleFix":"# before — replaying old widget data\nbody.telegram_auth = staleWidgetData\n# after — always collect fresh data at confirm time\ndata = Telegram.LoginWidget.auth();  # fresh, then POST immediately\nbody.telegram_auth = data;","handlingStrategy":"validation","validationCode":"// Client: check freshness before sending telegram_auth\nconst auth = Telegram.LoginWidget.auth();\nif (Date.now() / 1000 - Number(auth.auth_date) > 300) {\n  throw new Error('Telegram login data stale — re-authenticate');\n}\nawait confirmLink({ telegram_auth: auth });","typeGuard":"function isFreshTelegramAuth(a: Record<string, string>): boolean {\n  const age = Date.now() / 1000 - Number(a.auth_date);\n  return Number.isFinite(age) && age < 300 && Boolean(a.hash);\n}","tryCatchPattern":"try { await confirmLink(body); }\ncatch (e) {\n  if (e.status === 403 && e.detail?.includes('verification')) {\n    await retriggerTelegramLogin(); // get fresh widget data, retry once\n  } else throw e;\n}","preventionTips":["Always collect Telegram widget data at confirm time, never persist it for later.","Keep TELEGRAM_BOT_TOKEN identical across the bot and all backend environments.","Sync server clocks (NTP) so auth_date freshness checks don't false-fail."],"tags":["telegram","authentication","http-403","hmac","platform-linking"],"backgroundTag":null,"analyzedSha":"9c8bb5550f446ba5d3046b78896578742495b3cf","analyzedAt":"2026-08-14T17:17:21.957Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}