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
- Ensure the mandate is not modified between SignAP2Mandate and VerifyAP2Mandate; re-sign if any field (including bound task/context) changes.
- Verify you are using the public key corresponding to the keyID the mandate was signed with (check key rotation/lookup).
- Confirm both sides run compatible versions of the ap2Payload canonicalization code.
- 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
- Never mutate a mandate after signing; bind to task/message before signing (AP2BindMandateToMessage).
- Resolve the public key via the mandate's keyID and keep key-rotation lookups current.
- Keep signer and verifier on the same version of the payload canonicalization code.
- Log verification failures with keyID and mandate ID for security auditing.
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
- ap2: invalid signature encoding: %w
- ap2: marshal mandate: %w
- ap2: mandate id is required
- ap2: mandate kind is required
- push callback scheme %q not allowed (want http or https)
AI-assisted analysis of micro/go-micro@24529f1404 (2026-09-01).
Data as JSON: /api/errors/684c9477624d838d.
Report an issue: GitHub.