signalapp/Signal-Server · error · BackupFailedZkAuthenticationException

backup auth credential presentation verification failed

Error message

backup auth credential presentation verification failed

What it means

BackupFailedZkAuthenticationException thrown during backup authentication when presentation.verify(clock.instant(), serverSecretParams) raises VerificationFailedException for the backup auth credential presentation. The zero-knowledge proof embedded in the presentation does not verify against the server's secret parameters, so the request is rejected before any signature or authorization checks. A failure metric tagged presentation_verification is emitted for every occurrence.

Solutions

  1. Regenerate the backup auth credential and presentation with the same serverSecretParams the server uses
  2. Confirm client and server are in the same environment (matching public/secret parameter set)
  3. Serialize the presentation exactly once, as produced by the ZK library, without intermediate re-parsing
  4. Check client ZK credential library version compatibility with the server; upgrade if parameters changed

Example fix

// before
byte[] body = partiallyReparsedPresentation(); // proof bytes corrupted
authenticateBackup(body); // presentation verification failed
// after
byte[] body = presentation.serialize(); // single canonical serialization from ZK lib
authenticateBackup(body);
Defensive patterns

Strategy: validation

Validate before calling

if (!paramsEnv.equals(serverEnv)) {
  throw new IllegalStateException("credential minted with wrong serverSecretParams environment");
}
// verify locally with the server's public parameters before sending
presentation.verify(Instant.now(), serverPublicParams);

Try / catch

try { authenticateBackup(presentation, signature); }
catch (BackupFailedZkAuthenticationException e) {
  regenerateCredentialAndPresentation(); // proof unverifiable: mint a fresh credential
}

Prevention

When it happens

Trigger: Presenting a backup auth credential whose ZK proof is malformed, was created against different serverSecretParams (staging vs production keys), or was truncated/tampered in transit; also credentials generated by an incompatible client ZK library version.

Common situations: Pointing a dev client at production (or vice versa) so credentials are minted under the wrong server params; serializing the presentation incorrectly (re-encoding after partial parsing); replaying a presentation after the server rotated secret params; fuzzed or corrupted request bodies.

Related errors


AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09). Data as JSON: /api/errors/2664b7e79d5ee111. Report an issue: GitHub.

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/backup/BackupManager.java:752

    Pair<BackupCredentialType, BackupLevel> verifySignature(byte[] signature, ECPublicKey publicKey) throws BackupFailedZkAuthenticationException;
  }

  /**
   * Verify the presentation was issued by us, which should be done before checking the stored public key
   *
   * @param presentation A ZK credential presentation that encodes the backupId and the receipt level of the requester
   * @return A function that can be used to verify a signature provided with the presentation
   */
  private PresentationSignatureVerifier verifyPresentation(final BackupAuthCredentialPresentation presentation)
      throws BackupFailedZkAuthenticationException {
    try {
      presentation.verify(clock.instant(), serverSecretParams);
    } catch (VerificationFailedException e) {
      Metrics.counter(ZK_AUTHN_COUNTER_NAME,
              SUCCESS_TAG_NAME, String.valueOf(false),
              FAILURE_REASON_TAG_NAME, "presentation_verification")
          .increment();
      throw new BackupFailedZkAuthenticationException("backup auth credential presentation verification failed");
    }
    return (signature, publicKey) -> {
      if (!publicKey.verifySignature(presentation.serialize(), signature)) {
        Metrics.counter(ZK_AUTHN_COUNTER_NAME,
                SUCCESS_TAG_NAME, String.valueOf(false),
                FAILURE_REASON_TAG_NAME, "signature_validation")
            .increment();
        throw new BackupFailedZkAuthenticationException("backup auth credential presentation signature verification failed");
      }
      return new Pair<>(presentation.getType(), presentation.getBackupLevel());
    };
  }

  /**
   * Check that the authenticated backup user is authorized to use the provided backupLevel
   *
   * @param backupUser  The backup user to check
   * @param backupLevel The authorization level to verify the backupUser has access to

View on GitHub (pinned to 100ab61c82)