AI Research Library

A2A Tasks, Artifacts and Inter-Agent Authority

Rajesh Ranjan Mahapatra

A2A can carry long-running work between independent agents, but a protocol task is not a permission. Each consequential hop needs task-bound authority, independently accepted artifacts and verified outcomes.

© 2026 Rajesh Ranjan Mahapatra. 32 min read

A2A Tasks, Artifacts and Inter-Agent Authority

A2A can carry long-running work between independent agents, but a protocol task is not a permission. Each consequential hop needs task-bound authority, independently accepted artifacts and verified outcomes.

TLDR

  1. A2A standardises discovery, messages, tasks, lifecycle states and artifacts. It does not make a remote agent authorised to act for a person, organisation or case.
  2. The decisive mechanism is separation: task state coordinates work, authority leases constrain effects, artifact attestations preserve provenance, and resource-local checks decide whether an operation is allowed.
  3. Never forward ambient bearer power. Exchange a narrower grant bound to subject, actor, audience, task, resource, operation, purpose, evidence state, expiry and replay rules.
  4. AUTH_REQUIRED, COMPLETED, a signed Agent Card and a valid artifact each prove something useful. None alone proves business approval, factual validity or observed effect.
  5. Adopt A2A for independent, long-running collaborators only when protocol conformance and authority conformance are tested separately. Use a simpler call for local, reversible, low-consequence work.

A fictional bank is preparing the annual review of Northwind Renewables. Its case agent can read the authorised credit file, but a specialist operated by another company performs covenant extraction. The case agent discovers that specialist through an Agent Card, sends a request, receives a task identifier and watches the task move from submitted to working. Halfway through, the specialist returns TASK_STATE_AUTH_REQUIRED. It needs access to a licensed document repository before it can finish.

The easy implementation forwards the case agent's existing bearer token. The task resumes and ends in TASK_STATE_COMPLETED. A polished covenant report arrives as an artifact. Every protocol event looks healthy. Yet the forwarded token can read every case assigned to the relationship manager, not merely the two documents needed for this task. It is valid for forty-five minutes, while the delegated work takes three. The remote agent can also reuse it outside the A2A task. The protocol exchange succeeded while the authority design failed.

Now change only one feature. Issue the specialist a three-minute grant that names the represented user, the calling agent, the receiving agent, the task, the two document identifiers, the read operation and the annual-review purpose. Bind it to the current case-state digest. Forbid redelegation. Mark the nonce as consumed after use. The specialist receives enough power to complete the task, but no ambient power survives the hop.

This is the central answer. A2A should move task state and deliverables across an agent boundary; a separate authority mechanism should move only the minimum right needed for one bounded operation. The two lifecycles interact, but neither may silently stand in for the other. The current A2A 1.0 specification makes that boundary explicit: the AUTH_REQUIRED state signals that more authorisation is needed, while leaving the scope, representation, validity and revocation of that authorisation to the implementation, credential issuer or extension.[1]

Part I

The protocol coordinates work

A remote agent is different from a local function. It may run in another process, release on another schedule, use another framework, hold different credentials and remain opaque to the caller. Work can outlive an HTTP response. The remote side may request clarification, pause for authorisation, stream partial artifacts, fail after producing useful intermediate state or continue after the original client disconnects.

A2A gives those interactions a common vocabulary. The current released specification defines interoperable operations over JSON-RPC, HTTP with JSON and gRPC. A client can discover an agent's advertised skills and security schemes, send a message, receive either an immediate message or a stateful task, subscribe to updates, retrieve a task later and obtain artifacts.[1] The official task guidance describes contextId as a grouping identifier for related messages and tasks, and a task as the stateful unit that progresses towards an interrupted or terminal state.[2]

That is valuable precisely because it avoids embedding one operator's workflow engine inside another operator's product. The caller does not need the callee's private plan, memory architecture or tool graph. It needs a stable contract for requesting work, observing progress and receiving a deliverable. A2A standardises the seam, not the internal mind of either agent.

The cross-domain task lifecycle needs a second rail

Swipe horizontally to inspect the complete figure.

A2A task lifecycle with a separate authority railA caller discovers a remote agent, sends a message, receives a task, handles an authorization pause, accepts an artifact and verifies an effect. Below, a separate authority rail issues, narrows, consumes and closes a task-bound grant. Protocol railAuthority and evidence rail AgentCard Sendmessage Taskworking AUTHREQUIRED Artifactupdate Taskcompleted Get pause asks for authority, it does not create it Identifysubject + actor Issuebounded grant Verifyat receiver Verifyat resource Attestartifact Consumeor expire Protocol progress can continue only while the separate grant remains valid for the next operation.
Figure 1. Cross-domain task lifecycle. Illustrative synthesis. The upper rail follows A2A task concepts; the lower rail is a practitioner control pattern. The dotted join means that AUTH_REQUIRED may trigger an authority process but cannot substitute for it.

The coordination win has a boundary

A protocol can authenticate a calling workload, protect the transport and scope task visibility to a caller. Those are necessary controls. They do not answer the business question, “May this agent perform this exact operation on this resource for this purpose on behalf of this person now?” A service identity identifies the software making the request. A business principal identifies whose rights or duties are represented. A task identifier identifies protocol work. These are different entities.

The distinction becomes visible in long-running work. At 09:00, the caller may be entitled to request a document analysis. At 09:04, the case may close, the user's assignment may change or the policy version may be superseded. The remote task can still exist, yet its authority may have expired. Conversely, a valid business approval can exist before an A2A task is created. Task existence, task continuity and task success are facts about coordination, not proofs of continuing permission.

Published and official boundary

A2A 1.0 requires authenticated requests and authorisation scoping for task resources. It also states that the protocol does not define the scope or revocation semantics of authorisation obtained during an AUTH_REQUIRED pause. Research threat models therefore treat identity binding, replay, privilege escalation and task integrity as deployment concerns that must be tested around the protocol.[1][12][13]

Four objects, four proof limits

The cleanest way to prevent authority leakage is to say what each A2A object is allowed to mean. An Agent Card, Message, Task and Artifact are all useful. Trouble begins when one is promoted into evidence it was never designed to carry.

A2A object anatomy: useful meaning and forbidden inference
Discovery

Agent Card

Can establish: advertised endpoint, interfaces, protocol version, skills, capabilities and security schemes. A signature can protect card integrity when its trust path is accepted.

Cannot establish: that a skill is competent, safe for this case, authorised for this user or currently entitled to a downstream resource.

Communication

Message

Can establish: what one participant sent, associated task or context identifiers and typed text, file or data parts.

Cannot establish: that embedded instructions are trusted, that all messages will be retained or that critical output was durably delivered.

Coordination

Task

Can establish: server-issued task identity, current lifecycle state, context association, history selected by the server and attached artifacts.

Cannot establish: the represented business principal, the full mandate, the truth of an output, approval of a decision or occurrence of an external effect.

Deliverable

Artifact

Can establish: a named output with an identifier and one or more content parts associated with a task.

Cannot establish: acceptable provenance, untampered content, sufficient evidence, current entitlement, semantic correctness or a verified business outcome.

Figure 2. Four protocol objects should not impersonate four control systems. Source-derived interpretation of the A2A 1.0 data model, with practitioner statements of what each object does not prove.

The specification reinforces two of these limits. Results should be delivered as artifacts rather than ordinary messages, and messages must not be treated as a reliable mechanism for critical information because histories and streaming updates may be incomplete.[1] It also treats a server-generated contextId as an opaque grouping identifier. A context can preserve conversational continuity, but it should not be overloaded into a portable user identity or entitlement.

A signed Agent Card deserves the same discipline. Signing helps a client detect alteration and bind the card to a trusted signer. It does not certify the claims inside the card. A signed statement that an agent offers “credit decisioning” proves who made that statement, assuming the key is trusted. It does not prove that the agent may decide this customer's credit. Discovery and certification remain separate.

Thought experiment 1: change only the represented person

Hold the endpoint, caller agent, task text, context, resource and time fixed. Maya may read the covenant pack; Dev may view only workflow status. Both requests are sent by the same orchestrator workload. The A2A task can be identical at the wire level. If the remote side authorises only the service identity, it gives Dev whatever Maya could receive. The missing variable is the represented subject, not the task.

This thought experiment also reveals why putting a user name inside a message is insufficient. The content is controlled by the caller and may be influenced by a model. A receiving agent needs a verifiable binding from an accepted issuer between the subject and the actor. The human identity belongs in the authority decision, not in prose that the model can rewrite.

Thought experiment 2: change only the authorising state

Hold the subject, actor, task, operation and resource fixed. At 10:00, policy version seven permits access because the case is in annual review. At 10:03, the case enters legal hold and policy version eight blocks external retrieval. The same task and credential arrive at 10:04. A grant bound only to identity still passes; a grant bound to the earlier case-state digest fails. The missing variable is current authorising state.

Time alone cannot solve that problem. A one-minute token can be stale after ten seconds if the material state changes. A one-hour token may remain safe for an immutable public resource. Expiry limits exposure, while state binding limits semantic drift. High-consequence tasks often need both.

Part II

Authority must narrow at every hop

Suppose agent A may read one case and asks agent B to extract a covenant. B then asks agent C to interpret a registry filing. The dangerous implementation forwards A's token along the chain. Each new participant inherits the broadest power of the first participant, even if its subtask needs less. The token becomes ambient power: possession, rather than task fit, determines what can be done.

The safer mechanism is attenuation. Each hop receives a new grant whose authority is equal to or narrower than its parent. Let an authority set contain permitted subjects, actors, audiences, resources, operations, purposes, parameter ranges, times and delegation depths. For a chain of grants:

A₀ ⊇ A₁ ⊇ A₂ ⊇ … ⊇ Aₙ For every hop i: resource(Aᵢ₊₁) ⊆ resource(Aᵢ) operation(Aᵢ₊₁) ⊆ operation(Aᵢ) audience(Aᵢ₊₁) ⊆ audience(Aᵢ) time(Aᵢ₊₁) ⊆ time(Aᵢ) parameters(Aᵢ₊₁) ⊆ parameters(Aᵢ) delegation(Aᵢ₊₁) < delegation(Aᵢ) The notation describes a policy invariant. It does not prescribe one token format.

No downstream agent should be able to mint a right that the upstream grant did not contain. The default redelegation depth should be zero. Where a second hop is necessary, it should be explicit, observable and narrower again.

Ambient forwarding expands exposure; attenuation contracts it

Swipe horizontally to inspect the complete figure.

Ambient power compared with narrowing task-bound authorityThe upper path forwards one broad token to three agents, retaining a large authority cone. The lower path exchanges narrower grants at each hop until only one resource and operation remain. The same delegation chain, two authority geometries Ambient bearer forwarding ABCsame broad token Task-bound attenuation A: case read2 documents, 5 minB: extract1 document, 3 minC: verify field1 record, 60 sec Every hand-off reduces scope, audience, time or delegation depth.
Figure 3. Authority should form a narrowing cone. Illustrative. The exact token technology can vary; the invariant is monotonic attenuation and fresh verification at each recipient and protected resource.

A task-bound authority lease

One practical representation is a short-lived authority lease associated with a task but evaluated independently from it. “Lease” emphasises time and revocation without claiming a new standard. It can be implemented with established mechanisms. OAuth 2.0 Token Exchange distinguishes the subject on whose behalf a token is requested from the actor receiving delegated rights, and its act claim can represent a delegation chain.[5] Resource Indicators identify the protected resource, Rich Authorization Requests carry structured fine-grained permissions, and DPoP can sender-constrain a token so theft alone is insufficient for replay.[6][7][8]

These standards provide parts, not an automatic A2A authority profile. An implementation still needs a common meaning for task binding, purpose, evidence state, delegation depth and artifact acceptance. A lease for consequential work should normally carry or be resolvable to the following:

Minimum useful fields for one bounded inter-agent operation
FieldQuestion answeredFailure blocked
issuer, grant_idWho made this permission decision, and which decision is it?Self-issued or untraceable authority
subjectWhose rights, duties or consent are represented?Service identity replacing the human or business principal
actor, actor chainWhich workload is acting, and through which delegates?Confused deputy and hidden redelegation
audienceWhich receiving agent or resource may accept the grant?Token forwarding to an unintended service
task_id, context_idWhich unit of work may use it?Reuse in another task or conversation
resource, operationWhat may be touched, and how?Read authority becoming write or approval authority
purposeWhy is the operation permitted?Compatible data access used for an incompatible purpose
parameter boundsWhich values, amounts, regions or records are allowed?Unbounded execution inside a broad operation name
state or evidence digestWhich policy and world state justified the grant?True identity combined with obsolete authority
lifetime, nonce, use countWhen and how many times may it be used?Delayed use and replay
delegation depthMay the recipient delegate further?Unbounded transitive power
approval referenceWhich human or deterministic decision authorised it?Model proposal being mistaken for approval

Workload identity also needs its own foundation. SPIFFE, for example, gives a workload a verifiable identity inside a trust domain and can federate identities across domains.[10] That can establish “this is the covenant-reader workload run by the specialist”. It still does not establish “this workload may read Northwind's document for Maya's annual review”. Authentication answers who presented the request. The lease answers what that identified actor may do in this context.

Task state and authority state are coupled, not merged

A2A task lifecycle

submitted→working→auth required→working→completed

Coordinates remote work. Interrupted and terminal states come from the protocol.

Authority lifecycle

unissued→active→consumed/expired/revoked

Controls one operation. A task transition does not activate, renew or widen the grant.

Figure 4. There is no lawful arrow from “task working” to “authority active”. Illustrative. An implementation may trigger an authority workflow from task state, but a trusted issuer and policy decision must create the grant.

Check twice, at least

The receiving agent should validate the lease before it interprets the task as executable. The protected resource should validate again before releasing data or applying an effect. The second check matters because the agent is not the owner of the resource's policy. A model can propose an operation, and an agent host can approve it locally, while the resource still knows that the account is frozen, the document is sealed or the caller lacks regional entitlement.

OAuth security guidance recommends minimum necessary privileges, audience restriction and sender-constrained tokens where appropriate.[9] In an A2A estate, those principles become a chain invariant: every recipient verifies audience; every resource verifies its own policy; every new hop narrows rights; every consequential use is attributable to subject and actor; and every grant ends independently of the conversational context.

Practitioner synthesis

The task-bound authority lease is an architecture pattern, not part of A2A 1.0 and not a claim of a new cryptographic primitive. Emerging research such as Invocation-Bound Capability Tokens explores verifiable, attenuated delegation and provenance across A2A and MCP. Its reported results are promising but remain preprint evidence with an explicit threat model and implementation assumptions.[14]

Part III

The argument in one passChart · flow
flowchart TD
  A["The protocol coordinates work"] --> B["Four objects, four proof limits"]
  B --> C["Authority must narrow at every hop"]
  C --> D["Artifacts need acceptance, not<br/>admiration"]
  D -. "re-test" .-> A
  classDef first fill:#0a1424,stroke:#D95545,stroke-width:2px,color:#e6f3ff
  classDef step fill:#0a1424,stroke:#3f7da0,stroke-width:1px,color:#e6f3ff
  class A first
  class B,C,D step
A structural route through A2A Tasks, Artifacts and Inter-Agent Authority, from The protocol coordinates work to Interoperability should move work, not…. Reading use: follow the relation, then test it against the surrounding evidence and limits.

Artifacts need acceptance, not admiration

The remote agent finishes and attaches a report. The task is completed. What may the caller conclude?

It may conclude that the remote service reported successful completion and supplied an artifact associated with the task. It may not yet conclude that the artifact is authentic, complete, current, semantically correct or sufficient for the caller's decision. Protocol completion is a statement by the producer; artifact acceptance is a decision by the consumer.

This distinction is particularly important because A2A intentionally leaves artifact version relationships to the client. The official task guidance says the client is best placed to decide which artifact version is acceptable and that tracking artifact mutation is outside the protocol.[2] That is a sensible separation of concerns. It also means the consuming system needs an acceptance policy.

One task may need four different receipts

Protocol receipt

Task identifier, state transition, timestamps and retrieval history.

Proves: what the remote A2A endpoint reported.

Artifact receipt

Artifact identifier, digest, producer, media type, source references and acceptance result.

Proves: which deliverable was received and whether it passed the consumer's checks.

Authority receipt

Subject, actor, audience, operation, resource, policy decision, lifetime and consumed nonce.

Proves: why this operation was permitted at that moment.

Effect receipt

Observed postcondition from the authoritative system, including idempotency key and readback.

Proves: whether the intended external state change occurred exactly once.

Figure 5. “Completed” is one receipt among four. Illustrative practitioner synthesis. Read-only analysis may need the first three; a consequential mutation also needs an independently observed effect receipt.

An acceptance policy should validate structure before interpretation. Check the artifact's task and context bindings, content type, size, producer identity, digest and declared extensions. Treat text, files, URLs and structured data as untrusted input. The A2A media-type security requirements call for schema validation, sanitisation and protection against file-reference SSRF, while the sample repository warns implementers to treat external messages and artifacts as untrusted.[1][4]

Then validate evidential fitness. A covenant summary may need source document identifiers, page spans, extraction method, policy version, freshness and unresolved contradictions. A generated chart may need its dataset digest and transformation. A signed artifact proves integrity relative to a key; it does not prove that the producer used sufficient evidence. Provenance models such as W3C PROV distinguish entities, activities and agents, while in-toto attestations bind artifact subjects by digest.[11] Those concepts can inform an A2A artifact extension without pretending that software-build provenance and analytical evidence are identical.

Worked example 1: the negative control

A research agent asks a remote public-data agent for the latest released population table from a named government dataset. The service is publicly accessible, the operation is read-only, the result is reversible and no user-specific entitlement changes the answer. The caller authenticates the service, pins the agent endpoint, validates the artifact digest and source URL, and records the dataset release.

In this case, a bespoke task-bound user delegation token may add little. Ordinary service authentication plus artifact validation can be enough. This is the serious negative control: not every A2A task needs a represented human principal or a custom authority envelope. The mechanism becomes necessary when access or effects depend on who is represented, which case is in scope, why the data is used, what state authorised the operation or whether the remote agent may delegate again.

The negative control protects the argument from becoming “more controls are always better”. Controls create latency, coupling, operational state and failure modes. Apply them where one varying causal feature changes permission.

Effects require readback

Suppose the remote agent is asked to place a hold on a payment. It returns a completed task with an artifact saying “hold placed”. That statement is not an effect receipt. The downstream payment service may have timed out after accepting the command, applied the hold twice through retries or rejected it after the agent generated its report. The caller needs an idempotency key and an authoritative readback from the payment system.

A2A is the coordination envelope around the remote worker. It cannot transform the remote worker's narrative into ground truth about another system. The final control remains local to the effect owner: verify the postcondition, classify an ambiguous commit as an unknown outcome, and prevent retries from multiplying the effect.

A cross-domain worked case

Return to Northwind Renewables. The synthetic scenario has three operators. The bank runs the case orchestrator. A specialist company runs a covenant-reading agent. A data provider exposes the licensed filing repository. The bank and specialist deploy independently and cannot share application sessions or internal agent state.

The goal is narrow: produce an evidence pack for one annual review. The specialist may read two named filings and extract five covenant fields. It may not view other customer documents, approve a waiver, write into the credit system or delegate further.

Production-shaped delegation across three operators

Swipe horizontally to inspect the complete figure.

Cross-domain covenant evidence workflowA bank orchestrator sends an A2A task to a specialist agent. An authorization service issues a narrow lease. The specialist reads only two filings from a provider, returns an attested artifact, and the bank validates it before use. Bank trust domainSpecialist trust domainProvider trust domain Case orchestratorsubject Maya, case 472 Authority serviceissues 3-minute lease Covenant readerno redelegation Artifact builderdigest + source spans Filing repositoryresource-local policy Consumer acceptance gate A2A task narrow lease read 2 filings licensed data artifact + attestation approval ref No domain receives the bank user's ambient session or a token for unrelated cases.
Figure 6. The remote agent receives a task, the resource receives a bounded grant, and the caller receives an artifact. Synthetic worked scenario. No client deployment is implied.

Step 1: discover, then verify the discovery claim

The orchestrator retrieves the specialist's Agent Card over an approved channel. It checks the supported A2A interface, protocol version, relevant skill, security scheme and card signature. A policy registry confirms that this provider is approved for covenant extraction. The card helps routing; the registry and assurance evidence decide whether the provider may enter this workflow.

Step 2: create the task without smuggling power inside the message

The orchestrator sends a message that names the requested deliverable, document references and expected artifact schema. It does not include a reusable user token, a database connection or an instruction to “use any available source”. The specialist returns a server-generated task and begins work. The task is visible only to the authenticated and authorised caller.

Step 3: answer the authorisation pause out of band

The specialist reaches the licensed repository and transitions the task to TASK_STATE_AUTH_REQUIRED. The status message describes the requested operation in structured data. The bank's authority service evaluates Maya's assignment, case state, provider approval and purpose. It exchanges the upstream subject and actor information for a sender-constrained, audience-restricted grant naming the specialist, repository, two filing identifiers and read-only operation.

The A2A task stores no ambient secret. The orchestrator returns only a handle or protected credential through the agreed extension or secure channel. The specialist verifies the grant, and the repository verifies it again. The nonce is consumed on successful access. A policy change or task mismatch causes denial even if the A2A task still exists.

Step 4: produce an artifact that can be checked

The specialist creates a JSON artifact containing the five extracted fields, document and page references, extraction confidence, contradictions, producer identity, task and context identifiers, schema version and content digest. It transitions the task to completed. The bank does not yet copy the fields into the credit memo.

Step 5: accept, reject or quarantine

The bank validates the artifact schema, digest, producer, task binding and source references. It independently retrieves two cited spans and compares them with the extracted values. A contradiction moves the artifact to human review. A clean artifact becomes evidence for the next workflow step, not an approval of the annual review. The authority receipt, artifact receipt and protocol trace remain linked by task ID and grant ID.

This case shows the architecture change. The task carries coordination. The grant carries bounded authority. The artifact carries a deliverable plus provenance. The bank's acceptance gate carries accountable judgement. None is asked to do another's job.

Part IV

The A2A authority conformance lab

The official A2A Technology Compatibility Kit validates protocol implementations across gRPC, JSON-RPC and HTTP with JSON, organising tests around normative requirements and generating compatibility reports.[3] That answers an important question: does this endpoint speak the protocol correctly?

It does not, by itself, answer whether a bank's authority semantics are correct. That is not a criticism of the TCK. Business authority is intentionally implementation-specific. Protocol conformance and authority conformance are orthogonal release gates. A deployment can pass one and fail the other.

Conformance should be layered from syntax to verified outcome
5. Outcome conformanceWas the intended postcondition observed exactly once, or classified as unknown?
4. Artifact conformanceDoes the deliverable match task, producer, digest, schema, provenance and acceptance policy?
3. Authority conformanceDo subject, actor, audience, resource, operation, purpose, state, lifetime and replay rules hold?
2. InteroperabilityDo independently implemented clients and servers exchange tasks, streams, errors and artifacts?
1. Protocol conformanceDo schemas, methods, bindings and normative A2A behaviours match the specification and TCK?
Figure 7. The official TCK is the foundation, not the ceiling. Layers one and part of two align with official A2A tooling. Layers three to five are the article's practitioner extension for consequential systems.

What the lab varies

A good test does not merely replay one successful task. It changes one causal feature at a time and expects the policy to fail for the right reason. Keep the text constant and change the subject. Keep identity constant and widen the operation. Keep the task constant and alter the case-state digest. Replay a consumed nonce. Attach a valid artifact to another task. Modify one byte after calculating the digest.

The expected result is not always “reject the whole task”. An invalid invocation should be denied before the effect. A malformed artifact may be quarantined while the protocol task remains retrievable. A transient status message can be lost without losing the final artifact. The lab therefore tests typed outcomes: permit, deny, request input, quarantine, retry or mark unknown.

Runnable fixture runner

The browser runner tests the contract logic with synthetic values. It treats cryptographic signature verification as an injected boolean so the policy branches remain visible. The full Python script below signs and verifies a demo HMAC using only the standard library.

Ready.

Select “Run eight fixtures” to evaluate the positive and negative cases.
Executable Python 3.11 artifact: a2a_authority_lab.py

The script uses HMAC only to keep the demonstration dependency-free. It is not a production token profile. Expected output contains eight PASS lines: one allowed positive case and seven denied or quarantined mutations.

"""Synthetic A2A authority conformance lab.

The script demonstrates policy logic, not a production token format.
It uses HMAC only so the example is runnable with the Python standard library.
A real deployment should use its approved authorization server, asymmetric or
sender-constrained credentials, key rotation, revocation and resource-local policy.
"""

from __future__ import annotations

from copy import deepcopy
from datetime import datetime, timedelta, timezone
import hashlib
import hmac
import json
from typing import Any

DEMO_KEY = b"replace-with-a-real-key-management-system"
ALLOWED_TASK_STATES = {
    "TASK_STATE_SUBMITTED",
    "TASK_STATE_WORKING",
    "TASK_STATE_AUTH_REQUIRED",
}


def canonical_json(value: Any) -> bytes:
    return json.dumps(value, sort_keys=True, separators=(",", ":")).encode("utf-8")


def sha256_text(text: str) -> str:
    return hashlib.sha256(text.encode("utf-8")).hexdigest()


def sign(payload: dict[str, Any]) -> str:
    return hmac.new(DEMO_KEY, canonical_json(payload), hashlib.sha256).hexdigest()


def issue_lease(payload: dict[str, Any]) -> dict[str, Any]:
    return {"payload": deepcopy(payload), "signature": sign(payload)}


def verify_lease_signature(lease: dict[str, Any]) -> bool:
    supplied = str(lease.get("signature", ""))
    expected = sign(lease.get("payload", {}))
    return hmac.compare_digest(supplied, expected)


def parse_utc(value: str) -> datetime:
    parsed = datetime.fromisoformat(value.replace("Z", "+00:00"))
    if parsed.tzinfo is None:
        raise ValueError("timestamp must include a timezone")
    return parsed.astimezone(timezone.utc)


def authorize_invocation(
    *,
    task: dict[str, Any],
    lease: dict[str, Any],
    invocation: dict[str, Any],
    now: datetime,
    live_state_digest: str,
    consumed_nonces: set[str],
) -> tuple[bool, list[str]]:
    """Check whether one proposed remote operation is within the task-bound lease."""

    errors: list[str] = []
    payload = lease.get("payload", {})

    if not verify_lease_signature(lease):
        errors.append("invalid lease signature")

    if task.get("status") not in ALLOWED_TASK_STATES:
        errors.append("task is not in an invocable state")

    bindings = {
        "task_id": task.get("id"),
        "context_id": task.get("context_id"),
        "subject": invocation.get("subject"),
        "actor": invocation.get("actor"),
        "audience": invocation.get("target_agent"),
        "resource": invocation.get("resource"),
        "operation": invocation.get("operation"),
        "purpose": invocation.get("purpose"),
    }
    for field, actual in bindings.items():
        if payload.get(field) != actual:
            errors.append(f"{field} binding mismatch")

    amount = invocation.get("amount")
    maximum = payload.get("parameter_bounds", {}).get("max_amount")
    if amount is not None and maximum is not None and amount > maximum:
        errors.append("parameter bound exceeded")

    if payload.get("state_digest") != live_state_digest:
        errors.append("authorizing state has changed")

    try:
        not_before = parse_utc(payload["not_before"])
        expires_at = parse_utc(payload["expires_at"])
        if now < not_before:
            errors.append("lease not yet active")
        if now >= expires_at:
            errors.append("lease expired")
    except (KeyError, TypeError, ValueError):
        errors.append("invalid lease lifetime")

    requested_depth = int(invocation.get("delegation_depth", 0))
    max_depth = int(payload.get("max_delegation_depth", 0))
    if requested_depth > max_depth:
        errors.append("delegation depth exceeded")
    if requested_depth > 0 and not payload.get("may_redelegate", False):
        errors.append("redelegation forbidden")

    nonce = str(payload.get("nonce", ""))
    if not nonce:
        errors.append("missing nonce")
    elif nonce in consumed_nonces:
        errors.append("replay detected")

    if errors:
        return False, errors

    consumed_nonces.add(nonce)
    return True, ["task-bound authority accepted"]


def accept_artifact(
    *,
    task: dict[str, Any],
    artifact: dict[str, Any],
    expected_producer: str,
    allowed_media_types: set[str],
) -> tuple[bool, list[str]]:
    """Validate the returned deliverable separately from invocation authority."""

    errors: list[str] = []
    if artifact.get("task_id") != task.get("id"):
        errors.append("artifact belongs to another task")
    if artifact.get("context_id") != task.get("context_id"):
        errors.append("artifact context mismatch")
    if artifact.get("producer") != expected_producer:
        errors.append("unexpected artifact producer")
    if artifact.get("media_type") not in allowed_media_types:
        errors.append("unsupported artifact media type")

    content = str(artifact.get("content", ""))
    if artifact.get("digest") != sha256_text(content):
        errors.append("artifact digest mismatch")
    if not artifact.get("source_refs"):
        errors.append("artifact has no source references")

    return (not errors, errors or ["artifact accepted"])


def base_fixture() -> tuple[dict[str, Any], dict[str, Any], dict[str, Any], dict[str, Any], datetime, str]:
    now = datetime(2026, 8, 30, 8, 0, tzinfo=timezone.utc)
    state_digest = sha256_text("case-472|policy-v7|evidence-v19")
    task = {
        "id": "task-472",
        "context_id": "ctx-88",
        "status": "TASK_STATE_AUTH_REQUIRED",
    }
    payload = {
        "grant_id": "grant-901",
        "issuer": "https://auth.example.test",
        "subject": "user:maya",
        "actor": "spiffe://bank.test/agents/case-orchestrator",
        "audience": "spiffe://specialist.test/agents/covenant-reader",
        "task_id": task["id"],
        "context_id": task["context_id"],
        "resource": "credit-case:472",
        "operation": "read:covenant-evidence",
        "purpose": "annual-review",
        "parameter_bounds": {"max_amount": 0},
        "state_digest": state_digest,
        "not_before": now.isoformat().replace("+00:00", "Z"),
        "expires_at": (now + timedelta(minutes=5)).isoformat().replace("+00:00", "Z"),
        "max_delegation_depth": 0,
        "may_redelegate": False,
        "nonce": "once-77",
    }
    invocation = {
        "subject": payload["subject"],
        "actor": payload["actor"],
        "target_agent": payload["audience"],
        "resource": payload["resource"],
        "operation": payload["operation"],
        "purpose": payload["purpose"],
        "amount": 0,
        "delegation_depth": 0,
    }
    content = "Covenant evidence summary for synthetic case 472."
    artifact = {
        "artifact_id": "artifact-19",
        "task_id": task["id"],
        "context_id": task["context_id"],
        "producer": payload["audience"],
        "media_type": "application/json",
        "content": content,
        "digest": sha256_text(content),
        "source_refs": ["public-registry:synthetic-44", "policy:annual-review-v7"],
    }
    return task, issue_lease(payload), invocation, artifact, now, state_digest


def run_case(name: str, mutate: str | None = None) -> tuple[str, bool, list[str]]:
    task, lease, invocation, artifact, now, state_digest = base_fixture()
    consumed: set[str] = set()

    if mutate == "wrong_subject":
        invocation["subject"] = "user:dev"
    elif mutate == "broader_operation":
        invocation["operation"] = "approve:credit-limit"
    elif mutate == "stale_state":
        state_digest = sha256_text("case-472|policy-v8|evidence-v20")
    elif mutate == "expired":
        now += timedelta(minutes=10)
    elif mutate == "replay":
        consumed.add(lease["payload"]["nonce"])
    elif mutate == "artifact_task_swap":
        artifact["task_id"] = "task-999"
    elif mutate == "tampered_artifact":
        artifact["content"] += " altered"

    allowed, authority_notes = authorize_invocation(
        task=task,
        lease=lease,
        invocation=invocation,
        now=now,
        live_state_digest=state_digest,
        consumed_nonces=consumed,
    )
    if not allowed:
        return name, False, authority_notes

    accepted, artifact_notes = accept_artifact(
        task=task,
        artifact=artifact,
        expected_producer=lease["payload"]["audience"],
        allowed_media_types={"application/json"},
    )
    return name, accepted, artifact_notes


def main() -> None:
    fixtures = [
        ("positive", None, True),
        ("wrong subject", "wrong_subject", False),
        ("broader operation", "broader_operation", False),
        ("stale state", "stale_state", False),
        ("expired lease", "expired", False),
        ("replayed lease", "replay", False),
        ("artifact task swap", "artifact_task_swap", False),
        ("tampered artifact", "tampered_artifact", False),
    ]

    failures = 0
    for name, mutation, expected in fixtures:
        _, actual, notes = run_case(name, mutation)
        verdict = "PASS" if actual == expected else "FAIL"
        failures += verdict == "FAIL"
        print(f"{verdict:4} | {name:20} | decision={actual!s:5} | {', '.join(notes)}")

    if failures:
        raise SystemExit(f"{failures} fixture(s) did not match their expected decision")


if __name__ == "__main__":
    main()

Reading the test result correctly

A passing positive fixture means the exact synthetic invocation matched the lease and the artifact passed the selected checks. It does not establish that the source evidence is true, the model extraction is accurate or the key management is adequate. A negative fixture is more diagnostic: it shows that a specific mutation is detected at the intended boundary.

The highest-value metrics are therefore not generic task success and not raw protocol availability. Track cross-subject false permits, cross-task replay, stale-state permits, overbroad-operation permits, artifact task swaps, digest failures, unverified completion claims and unknown outcomes. Zero observed failures in a fixed fixture set is evidence about that fixture set, not proof against every adversary.

Failure injection should mutate one boundary at a time
MutationProtocol remains valid?Authority decisionArtifact decisionExpected diagnostic
No changeYesPermitAcceptAll bindings hold
Subject onlyYesDenyNot reachedSubject mismatch
Operation onlyYesDenyNot reachedScope widening
State digest onlyYesDenyNot reachedAuthorising state changed
Nonce replayYesDenyNot reachedSingle-use violation
Artifact task ID onlyYesPermitQuarantineCross-task substitution
Artifact content onlyYesPermitQuarantineDigest mismatch
Public read, user changesYesPermitAcceptNegative control: subject is irrelevant
Figure 8. Protocol validity can remain green while authority or artifact acceptance turns red. Synthetic test design. The final row is the negative control that prevents needless subject binding for genuinely public work.

Part V

How the claim changes under pressureChart · state
stateDiagram-v2
  [*] --> Claim
  state "The coordination win has a<br/>boundary" as Claim
  state "A task-bound authority lease" as Test
  state "Check twice, at least" as Revision
  Claim --> Test: expose mechanism
  Test --> Decision: evidence survives
  Test --> Revision: rival survives
  Revision --> Claim: narrow or rebuild
  Decision --> [*]
The revision loop begins with The coordination win has a boundary and keeps counterexamples inside the reasoning path. Reading use: follow the relation, then test it against the surrounding evidence and limits.

Failure injection and the architecture decision

The strongest competing design is simpler: keep all agents inside one process and call specialists as functions or tools. That design avoids a network protocol, cross-domain trust and independent deployment. Where it fits, it is often better. A2A earns its complexity when the remote participant owns its runtime and semantics, when work is long-running or asynchronous, when artifacts need a durable lifecycle, or when independently built agents must interoperate without a shared release.

A second objection says OAuth already solves delegation. OAuth provides mature building blocks for limited access, token exchange, audience restriction, fine-grained authorisation and sender constraint. It does not define A2A task states, artifact streaming, context grouping or task retrieval. A2A provides those coordination semantics while intentionally leaving business authorisation open. The two mechanisms are complementary because they solve different layers.

A third objection says the receiving agent should simply be trusted. Trust reduces some threats but does not remove accidental scope reuse, stale credentials, confused deputy behaviour, task mix-ups or incident reconstruction. Cross-domain systems fail through ordinary integration mistakes as often as through malicious agents. A narrow grant also protects a cooperative provider from receiving power it never wanted.

Choose the smallest inter-agent mechanism that preserves the needed boundary

Local and reversible

Same operator, short call, shared release, no durable artifact lifecycle.

Prefer: function call, typed tool or local workflow step.

Independent but low consequence

Different runtime or vendor, long-running work, public or low-sensitivity resources.

Prefer: A2A with service authentication, task scoping and artifact validation.

Independent and consequential

User or case-specific data, write effects, redelegation or changing authorising state.

Prefer: A2A plus task-bound authority, provenance and outcome verification.

Authority cannot be bounded

Ambient credentials, unknown actor chain, unverifiable artifacts or no authoritative readback.

Decision: do not delegate the consequential operation.

Figure 9. A2A is a boundary choice, not a default topology. Practitioner decision instrument. Consequence changes the controls around A2A; inability to constrain authority is a stop condition.

Release tests that matter

Before release, run the official TCK against every supported transport and version. Then test your own authority semantics against live policy and resource servers. Verify that task listing, retrieval, cancellation, subscription and push configuration reveal only authorised tasks. Inject expired credentials, wrong audiences, swapped tasks, excessive delegation depth, unavailable revocation services and duplicate notifications. A2A push delivery can be at least once, so receivers need idempotent processing and task-specific notification credentials.[1]

Run artifact attacks separately. Substitute another task's artifact. Preserve the digest but change provenance metadata. Preserve metadata but alter content. Supply a malicious file URL. Remove a required source reference. Stream chunks out of order. Send a completed task with no acceptable deliverable. The consumer must fail closed for consequential use without turning every malformed artifact into an unrecoverable protocol incident.

Finally, test effects. Drop the connection after the protected resource accepts a command but before the agent receives confirmation. Retry with the same idempotency key. Retry with a different key. Return a completed task while the resource is unavailable. The correct state may be “unknown outcome”, not “failed” and not “completed”. That uncertainty must be visible to the supervising workflow.

Explicit failure boundary

The task-bound lease does not make a compromised workload trustworthy. It does not repair a malicious authorisation server, a false approval, a corrupted source document, collusion between agents or an incorrect resource policy. State digests are useful only if the selected state is authoritative and complete. Artifact attestations are useful only if keys, producers and verification policy are trustworthy. A sender-constrained token still grants its holder the rights inside it.

The mechanism also stops helping when the business permission cannot be expressed before action. Some judgements require a human to see the actual proposed output, not merely a task description. In those cases, the remote agent may prepare an artifact under read authority, but approval and execution must wait for review of the concrete proposal. Do not pre-authorise an unspecified future effect because a task is expected to produce one.

Failure boundary

When the resource owner cannot independently verify a bounded grant and the caller cannot independently verify the returned artifact or effect, A2A should remain a communication channel only. It must not become the path for an irreversible operation.

A compact architecture decision record

Decision record for one proposed inter-agent boundary
QuestionEvidence requiredDefault decision
Does the callee deploy independently or own distinct semantics?Ownership and release boundaryIf no, prefer a local typed call
Can work outlive one request or produce versioned artifacts?Task horizon and recovery needsIf yes, A2A task lifecycle may earn its cost
Does permission depend on subject, case, purpose or live state?Policy decision variablesIf yes, require task-bound authority
Can every hop narrow and verify the grant?Actor chain, audience and delegation policyIf no, block consequential redelegation
Can the artifact be tied to producer, task, inputs and digest?Acceptance schema and provenanceIf no, treat it as untrusted advisory text
Can the effect owner return an authoritative postcondition?Readback and idempotency designIf no, keep action human-controlled or reversible
Do protocol and authority fixtures both pass?TCK report plus authority lab reportRelease only when both are green

Source ledger

The article targets A2A specification 1.0.0, the latest released version at technical review. Official specifications establish protocol and OAuth semantics. Research sources support the security boundary and competing delegation mechanisms. The worked cases, task-bound lease, four-receipt model, layered conformance stack and executable lab are practitioner synthesis.

  1. Official A2A Protocol Working Group. Agent2Agent Protocol Specification 1.0.0. Used for task, message, artifact, Agent Card, authentication, authorisation-scoping, extension and security semantics.
  2. Official A2A Protocol Working Group. Life of a Task. Used for contexts, parallel tasks, task continuity and client responsibility for artifact version acceptance.
  3. Official A2A Project. A2A Technology Compatibility Kit. Used for protocol conformance across gRPC, JSON-RPC and HTTP with JSON.
  4. Official A2A Project. A2A samples and security warning. Used for the rule that external Agent Cards, messages, artifacts and status data remain untrusted input.
  5. Standard IETF. RFC 8693, OAuth 2.0 Token Exchange. Used for subject, actor, delegation and impersonation semantics.
  6. Standard IETF. RFC 8707, Resource Indicators for OAuth 2.0. Used for intended protected-resource binding.
  7. Standard IETF. RFC 9396, OAuth 2.0 Rich Authorization Requests. Used for structured, fine-grained authorisation details.
  8. Standard IETF. RFC 9449, Demonstrating Proof of Possession. Used for sender-constrained OAuth tokens and replay resistance.
  9. Standard IETF. RFC 9700, OAuth 2.0 Security Best Current Practice. Used for minimum privilege, audience restriction and sender constraint.
  10. Official SPIFFE Project. SPIFFE Concepts. Used for workload identity and trust-domain distinctions.
  11. Standard W3C. PROV Data Model; in-toto. Attestation Statement v1. Used as adjacent provenance mechanisms, not as direct A2A artifact standards.
  12. Research Habler, Huang, Narajala and Kulkarni. Building a Secure Agentic AI Application Leveraging A2A Protocol. Threat-model analysis covering spoofing, replay, privilege escalation, prompt injection and task integrity.
  13. Research Anbiaee et al. Security Threat Modeling for Emerging AI-Agent Protocols. Comparative preprint supporting lifecycle-aware and protocol-centric risk analysis.
  14. Research Prakash. AIP: Agent Identity Protocol for Verifiable Delegation Across MCP and A2A. Emerging preprint and reference implementation for attenuated delegation and provenance-bound completion.
  15. Practitioner Schifter. What We Learned Putting A2A Into Production. A current field report showing why one deployment added asker identity and provenance through local conventions and an extension. It is experience from one system, not universal evidence.
  16. Practitioner The task-bound authority lease, four-receipt model, conformance layers, mutation matrix, worked banking scenario and lab are proposals in this article. They require validation inside each organisation's threat model, identity system, policy engine and resource estate.
The evidence conversationChart · sequence
sequenceDiagram
  participant Q as Question
  participant M as Mechanism
  participant E as Evidence
  participant D as Decision
  Q->>M: The protocol coordinates work
  M->>E: The coordination win has a boundary
  E-->>M: compare rival explanations
  E->>D: Interoperability should move work, not ambient power
  D-->>Q: revise scope or act
Question, mechanism, evidence and decision exchange the burdens developed in A2A Tasks, Artifacts and Inter-Agent Authority. Reading use: follow the relation, then test it against the surrounding evidence and limits.

Interoperability should move work, not ambient power

A2A solves a real systems problem. Independent agents need a shared way to advertise capabilities, exchange messages, manage long-running tasks, stream progress and deliver artifacts. Recreating those semantics as private RPC contracts across every pair of operators produces brittle integration and inconsistent recovery.

The architecture fails when interoperability is allowed to imply authority. An Agent Card advertises. A message communicates. A task coordinates. An artifact delivers. None can silently become the represented subject, business mandate, evidence acceptance decision or verified postcondition. The right design keeps protocol state, authority state, evidence state and effect state linked but distinct.

That changes the implementation decision. Use A2A at an authentic agent boundary. Authenticate workloads. Scope task visibility. When work touches user-specific data or consequential effects, issue a short-lived grant bound to subject, actor, audience, task, resource, operation, purpose and live authorising state. Narrow it at every hop. Verify it again at the resource. Consume or expire it independently from the task. Treat every returned artifact as untrusted until the consumer validates its binding, digest, provenance and fitness. For mutations, observe the real postcondition.

Then test two things separately. The official TCK should show that the endpoint speaks A2A. The authority conformance lab should show that wrong subjects, wider operations, stale state, replay and artifact substitution fail at the intended boundary. A green protocol report without those tests is interoperability evidence, not an assurance case.

The practical rule is simple: let A2A carry the work far enough to cross an organisational boundary, while letting authority travel only as far as one explicitly bounded operation.