phacility/phabricator · error · ConduitException

ERR-INVALID-CERTIFICATE

ERR-INVALID-CERTIFICATE

Error message

ERR-INVALID-CERTIFICATE

What it means

conduit.connect verifies authSignature against sha1(authToken . user_conduit_certificate) using phutil_hashes_are_identical (a timing-safe comparison). A mismatch means the signature was not computed over the correct token+certificate pair for that user. Timestamp skew is a separate error (ERR-INVALID-TOKEN), so this is purely a wrong-secret or wrong-construction failure.

Source

Thrown at src/applications/conduit/method/ConduitConnectConduitAPIMethod.php:138

            pht(
              'The request you submitted is signed with a timestamp, but that '.
              'timestamp is not within %s of the current time. The '.
              'signed timestamp is %s (%s), and the current server time is '.
              '%s (%s). This is a difference of %s seconds, but the '.
              'timestamp must differ from the server time by no more than '.
              '%s seconds. Your client or server clock may not be set '.
              'correctly.',
              phutil_format_relative_time($threshold),
              $token,
              date('r', $token),
              $now,
              date('r', $now),
              ($token - $now),
              $threshold));
      }
      $valid = sha1($token.$user->getConduitCertificate());
      if (!phutil_hashes_are_identical($valid, $signature)) {
        throw new ConduitException('ERR-INVALID-CERTIFICATE');
      }
      $session_key = id(new PhabricatorAuthSessionEngine())->establishSession(
        PhabricatorAuthSession::TYPE_CONDUIT,
        $user->getPHID(),
        $partial = false);
    } else {
      throw new ConduitException('ERR-NO-CERTIFICATE');
    }

    return array(
      'connectionID'  => mt_rand(),
      'sessionKey'    => $session_key,
      'userPHID'      => $user->getPHID(),
    );
  }

}

View on GitHub (pinned to 5720a38cfe)

Solutions

  1. Re-fetch the certificate: generate a new token, call conduit.getcertificate with it, and use the returned certificate.
  2. Verify the client signs exactly sha1((string)token . certificate) with the same token it sends as authToken.
  3. If problems persist, confirm clocks (skew produces ERR-INVALID-TOKEN, not this error) and that the username matches the certificate owner.

Example fix

# before: stale cached certificate
$ rm -f ~/.arcrc && arc install-certificate <token>
# after: arc fetches and stores the current certificate, then
$ arc call-conduit user.whoami
Defensive patterns

Strategy: try-catch

Try / catch

try {
  $result = $call->execute();
} catch (ConduitException $ex) {
  if ($ex->getMessage() === 'ERR-INVALID-CERTIFICATE') {
    // Drop cached credentials and re-run the certificate handshake once.
  }
}

Prevention

When it happens

Trigger: Client cached an old certificate after it was rotated/regenerated; signature computed over a different concatenation or encoding than sha1(token + certificate); mixing one user's token with another user's certificate.

Common situations: Stale ~/.arcrc credentials after an admin regenerated conduit certificates; hand-rolled clients reimplementing the handshake and getting the concatenation order wrong.

Understand the failure class

Related errors


AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21). Data as JSON: /api/errors/830920bbda9d1d55. Report an issue: GitHub.