{"record":{"id":"3ff6d2c55773f518","repo":"phacility/phabricator","slug":"err-bad-token","errorCode":"ERR-BAD-TOKEN","errorMessage":"ERR-BAD-TOKEN","messagePattern":"ERR-BAD-TOKEN","errorType":"error_code","errorClass":"ConduitException","httpStatus":null,"severity":"error","filePath":"src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php","lineNumber":59,"sourceCode":"\n  protected function execute(ConduitAPIRequest $request) {\n    $failed_attempts = PhabricatorUserLog::loadRecentEventsFromThisIP(\n      PhabricatorConduitCertificateFailureUserLogType::LOGTYPE,\n      60 * 5);\n\n    if (count($failed_attempts) > 5) {\n      $this->logFailure($request);\n      throw new ConduitException('ERR-RATE-LIMIT');\n    }\n\n    $token = $request->getValue('token');\n    $info = id(new PhabricatorConduitCertificateToken())->loadOneWhere(\n      'token = %s',\n      trim($token));\n\n    if (!$info || $info->getDateCreated() < time() - (60 * 15)) {\n      $this->logFailure($request, $info);\n      throw new ConduitException('ERR-BAD-TOKEN');\n    } else {\n      $log = PhabricatorUserLog::initializeNewLog(\n          $request->getUser(),\n          $info->getUserPHID(),\n          PhabricatorConduitCertificateUserLogType::LOGTYPE)\n        ->save();\n    }\n\n    $user = id(new PhabricatorUser())->loadOneWhere(\n      'phid = %s',\n      $info->getUserPHID());\n    if (!$user) {\n      throw new Exception(pht('Certificate token points to an invalid user!'));\n    }\n\n    return array(\n      'username'    => $user->getUserName(),\n      'certificate' => $user->getConduitCertificate(),","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/phacility/phabricator/blob/5720a38cfe95b00ca4be5016dd0d2f3195f4fa04/src/applications/conduit/method/ConduitGetCertificateConduitAPIMethod.php#L41-L77","documentation":"conduit.getcertificate looks up the trimmed 'token' value in phabricator_conduit_certificate_token and requires the row to be no older than 15 minutes. A missing row (unknown token) or an expired one (>900s old) both yield 'ERR-BAD-TOKEN', and the failure is logged against the requesting IP.","triggerScenarios":"Delaying more than 15 minutes between generating the token and redeeming it; reusing a token from a previous session; a token truncated or altered by shell quoting/whitespace.","commonSituations":"Debugging a client step-by-step so the token expires in between; caching tokens in scripts or docs instead of minting them fresh per run.","solutions":["Generate a new token and call conduit.getcertificate with it immediately, within the 15-minute validity window.","Verify the token is transmitted intact (no trailing newline/whitespace; it is trimmed server-side but must otherwise match exactly).","If failures repeat, stop quickly: five failures per IP per 5 minutes trigger ERR-RATE-LIMIT."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  $result = $call->execute();\n} catch (ConduitException $ex) {\n  if ($ex->getMessage() === 'ERR-BAD-TOKEN') {\n    // Mint a NEW token and retry immediately once; old tokens cannot be revived.\n  }\n}","preventionTips":["Generate the token immediately before redeeming it; the lifetime is only 15 minutes.","Never persist or reuse tokens across runs.","Abort after a couple of failures to avoid tripping ERR-RATE-LIMIT (5 failures / 5 min / IP)."],"tags":["conduit","auth","token","phabricator","php"],"backgroundTag":"invalid-auth-token","analyzedSha":"5720a38cfe95b00ca4be5016dd0d2f3195f4fa04","analyzedAt":"2026-08-21T05:07:25.672Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}