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
- Regenerate the backup auth credential and presentation with the same serverSecretParams the server uses
- Confirm client and server are in the same environment (matching public/secret parameter set)
- Serialize the presentation exactly once, as produced by the ZK library, without intermediate re-parsing
- 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
- Verify the presentation locally against server public params before sending
- Never re-serialize or transform the presentation after the ZK library produces it
- Keep client/server ZK parameter environments matched (no staging/prod mixing)
- Track server secret-param rotations and re-mint credentials after them
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
- backup auth credential presentation signature verification…
- Only primary device can set backup-id
- Must set at least one of message/media credential requests
- receipt credential presentation verification failed
- Invalid sourceObject size
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 toView on GitHub (pinned to 100ab61c82)