phacility/phabricator · error · Exception
Invalid response token for this challenge: token digest does
Error message
Invalid response token for this challenge: token digest does not match stored digest.
What it means
PhabricatorAuthChallenge::setResponseToken() digests the offered response token with PhabricatorHash::digestWithNamedKey(). If the challenge already carries a responseDigest (persisted on an earlier leg), the fresh digest must satisfy phutil_hashes_are_identical() against the stored one; any difference means the response token changed between requests and the exception fires.
Source
Thrown at src/applications/auth/storage/PhabricatorAuthChallenge.php:213
pht(
'This challenge already has a response token; you can not '.
'set a new response token.'));
}
if (preg_match('/ /', $token->openEnvelope())) {
throw new Exception(
pht(
'The response token for this challenge is invalid: response '.
'tokens may not include spaces.'));
}
$digest = PhabricatorHash::digestWithNamedKey(
$token->openEnvelope(),
self::TOKEN_DIGEST_KEY);
if ($this->responseDigest !== null) {
if (!phutil_hashes_are_identical($digest, $this->responseDigest)) {
throw new Exception(
pht(
'Invalid response token for this challenge: token digest does '.
'not match stored digest.'));
}
} else {
$this->responseDigest = $digest;
}
$this->responseToken = $token;
return $this;
}
public function getResponseToken() {
return $this->responseToken;
}
public function setResponseDigest($value) {View on GitHub (pinned to 5720a38cfe)
Solutions
- Restart the authentication/MFA flow to obtain fresh challenges and matching response tokens
- Make the client submit each challenge response exactly once, unmodified
- Guard forms against double submission (disable submit on click) so a second, different token never reaches the server
Defensive patterns
Strategy: try-catch
Try / catch
try {
$challenge->setResponseToken($token_envelope);
} catch (Exception $ex) {
// Digest mismatch: the flow's state changed (replay/double submit).
// Abort this attempt and restart the MFA flow - do not resubmit the
// same challenge with another minted token.
return $this->newDialog()
->setTitle(pht('MFA Session Expired'))
->addSubmitButton(pht('Restart'));
} Prevention
- Submit each MFA challenge response exactly once and never regenerate the token client-side
- Disable submit buttons on first click to prevent double submissions with different tokens
- On any MFA error, restart the whole flow to get fresh challenges rather than retrying pieces
When it happens
Trigger: Calling setResponseToken() with a different token than the one already recorded for the challenge - replaying an old MFA form after the challenge was answered, double submission where the client minted a new token, or a client that regenerates tokens per attempt against the same stored challenge.
Common situations: Back-button resubmission of an MFA prompt; JS double-fire submitting two different token values; scripts replaying captured MFA responses; concurrent attempts on one challenge.
Related errors
- The "Has MFA" query constraint may only be used by administr
- This comment was signed with MFA, so edits to it must also b
- This transaction group requires MFA to apply, but you can no
- Your account has too many outstanding, incomplete MFA synchr
- This Duo enrollment attempt is invalid or has expired ("%s")
AI-assisted analysis of phacility/phabricator@5720a38cfe (2026-08-21).
Data as JSON: /api/errors/9b43bd5c4560679d.
Report an issue: GitHub.