Skip to main content

Overview

Every verification verdict is signed with an ES256 JWT attestation — a cryptographic proof that the verification took place. This enables:
  • Tamper detection — any modification invalidates the signature
  • Non-repudiation — the signing service is identified by DID
  • Audit compliance — attestations are stored and queryable
  • Cross-service verification — any QWED node can verify the token

How it works


JWT structure

{
  "alg": "ES256",
  "typ": "qwed-a2a-attestation+jwt",
  "kid": "did:qwed:a2a:local#signing-key-v1"
}

Payload

{
  "iss": "did:qwed:a2a:local",
  "sub": "sha256:e3b0c44298fc1c149afb...",
  "iat": 1711411200,
  "exp": 1711497600,
  "jti": "a2a_trace_001",
  "qwed_a2a": {
    "version": "1.0",
    "verdict": "forwarded",
    "engine": "finance_guard",
    "sender": "procurement-agent",
    "receiver": "treasury-agent"
  }
}
ClaimDescription
issDID-based issuer identity of the signing service
subSHA-256 hash of the original payload (tamper detection)
iatToken issued-at timestamp
expToken expiration (default: 24 hours)
jtiTrace ID linking to the verification event
qwed_a2aQWED-specific claims: verdict, engine, sender/receiver

Signing a verdict

from qwed_a2a.security.crypto import A2ACryptoService

crypto = A2ACryptoService(
    issuer_id="did:qwed:a2a:production",
    validity_seconds=86400,  # 24 hours
)

token = crypto.sign_verdict(
    trace_id="a2a_audit_001",
    verdict_status="forwarded",
    engine="finance_guard",
    sender_id="procurement-agent",
    receiver_id="treasury-agent",
    payload_hash="sha256:abc123...",
)

print(token)
# eyJhbGciOiJFUzI1NiIsInR5cCI6InF3ZWQtYTJhLWF0dGVzdGF0aW9uK2p3dCIs...

Verifying an attestation

is_valid, claims, error = crypto.verify_attestation(token)

if is_valid:
    print(f"Verdict: {claims['qwed_a2a']['verdict']}")
    print(f"Engine:  {claims['qwed_a2a']['engine']}")
    print(f"Trace:   {claims['jti']}")
else:
    print(f"Invalid: {error}")

Verification outcomes

ResultMeaning
(True, claims, None)Valid attestation — claims are trustworthy
(False, None, "Attestation has expired")Token past its exp time
(False, None, "Invalid token: ...")Signature mismatch, tampering, or wrong key

Tamper detection

The sub claim contains a SHA-256 hash of the original payload:
payload_hash = A2ACryptoService.hash_content(
    '{"claimed_total": 150.00, "line_items": [...]}'
)
# "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
If the original payload is modified after signing, the hash will not match the sub claim — even though the JWT signature itself is still valid. Always verify both the JWT signature and the payload hash.

Cross-service isolation

Each A2ACryptoService instance generates its own ECDSA P-256 key pair. Tokens signed by one instance cannot be verified by another:
service_a = A2ACryptoService(issuer_id="did:qwed:a2a:node-A")
service_b = A2ACryptoService(issuer_id="did:qwed:a2a:node-B")

token = service_a.sign_verdict(...)

is_valid, _, error = service_b.verify_attestation(token)
# is_valid = False — different key pairs
For multi-node deployments, share the same key pair across instances or implement a key distribution protocol. See Deployment for details.

Graceful degradation

If cryptography and PyJWT packages are not installed, the interceptor operates without attestations. Verdicts are still generated, but attestation_jwt will be None.
from qwed_a2a.security.crypto import HAS_CRYPTO

if HAS_CRYPTO:
    print("✅ Crypto available — attestations enabled")
else:
    print("⚠️ Crypto unavailable — attestations disabled")