micro/go-micro · error

ap2: mandate signature verification failed

Error message

ap2: mandate signature verification failed

What it means

VerifyAP2Mandate recomputes the canonical payload from the mandate and checks its Ed25519 signature with the supplied public key. This error is returned when ed25519.Verify fails, meaning the signature does not match the payload bytes — the credential is unauthenticated or has been altered in transit.

Source

Thrown at gateway/a2a/ap2.go:94

	payload, err := ap2Payload(m)
	if err != nil {
		return AP2SignedMandate{}, err
	}
	return AP2SignedMandate{Mandate: m, KeyID: keyID, Signature: base64.RawURLEncoding.EncodeToString(ed25519.Sign(private, payload))}, nil
}

// VerifyAP2Mandate verifies a signed mandate credential.
func VerifyAP2Mandate(s AP2SignedMandate, public ed25519.PublicKey) error {
	sig, err := base64.RawURLEncoding.DecodeString(s.Signature)
	if err != nil {
		return fmt.Errorf("ap2: invalid signature encoding: %w", err)
	}
	payload, err := ap2Payload(s.Mandate)
	if err != nil {
		return err
	}
	if !ed25519.Verify(public, payload, sig) {
		return errors.New("ap2: mandate signature verification failed")
	}
	return nil
}

// AP2BindMandateToMessage returns a copy of m bound to the A2A message's task/context.
func AP2BindMandateToMessage(m AP2Mandate, msg Message) AP2Mandate {
	m.TaskID = msg.TaskID
	m.ContextID = msg.ContextID
	return m
}

// AP2AttachMandate returns a copy of msg carrying the signed AP2 mandate.
func AP2AttachMandate(msg Message, mandate AP2SignedMandate) Message {
	msg.AP2Mandates = append(append([]AP2SignedMandate{}, msg.AP2Mandates...), mandate)
	return msg
}

// VerifyAP2ForTask verifies signature, task binding, and optional settlement rail reference.

View on GitHub (pinned to 24529f1404)

Solutions

  1. Ensure the mandate is not modified between SignAP2Mandate and VerifyAP2Mandate; re-sign if any field (including bound task/context) changes.
  2. Verify you are using the public key corresponding to the keyID the mandate was signed with (check key rotation/lookup).
  3. Confirm both sides run compatible versions of the ap2Payload canonicalization code.
  4. Treat verification failure as a security event: reject the credential and log/alert rather than retrying blindly.

Example fix

// before
// mandate fields mutated after signing
m.Priority = "high"
err := ap2.VerifyAP2Mandate(signed, pub) // fails

// after
err := ap2.VerifyAP2Mandate(signed, pub)
if err != nil {
	return fmt.Errorf("rejecting unverified mandate: %w", err)
}
Defensive patterns

Strategy: try-catch

Try / catch

if err := ap2.VerifyAP2Mandate(signed, pub); err != nil {
	if strings.Contains(err.Error(), "signature verification failed") {
		// reject credential, log security event, do not retry
		return ErrUntrustedMandate
	}
	return err
}

Prevention

When it happens

Trigger: Calling VerifyAP2Mandate with a signed mandate whose signature was computed over a different payload: the mandate was modified after signing, the wrong public key is used, or the payload serialization (ap2Payload) differs between signer and verifier.

Common situations: A tampered mandate passing through an untrusted intermediary; key rotation where the verifier holds the old public key; rebinding a mandate to a different A2A task/message after signing; version mismatches in payload canonicalization between services.

Related errors


AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01). Data as JSON: /api/errors/684c9477624d838d. Report an issue: GitHub.