Multi-turn tasks: input-required and auth-required
How A2A tasks pause for input or authorization, how to continue them on the same taskId, which ID mismatches agents must reject, and what the spec leaves open.
A2A tasks do not have to finish in one exchange. An agent can stop a task partway and wait for the client in one of two interrupted states: TASK_STATE_INPUT_REQUIRED when it needs more information, and TASK_STATE_AUTH_REQUIRED when it needs authorization. The client continues the same task by sending a new message that carries the task’s taskId. The specification is strict about identifiers: a taskId must point to an existing task, a contextId that contradicts the task must be rejected, and a contextId the agent cannot accept must be refused rather than silently replaced.
AUTH_REQUIRED adds a second layer. The credential usually travels out of band, straight to the agent, and the protocol does not say what that credential means. Its scope, format, lifetime and revocation are left to implementations and extensions. This guide covers the rules for both states, what a client should show the person behind it, timeouts and cancellation, and ends with a live exchange. For every state in the lifecycle, see the A2A task lifecycle.
The two interrupted states
TASK_STATE_INPUT_REQUIRED |
TASK_STATE_AUTH_REQUIRED |
|
|---|---|---|
| The agent needs | More information to continue | Authorization to continue, such as an OAuth token or a person’s approval |
| Where the need is described | status.message |
status.message, unless the details were agreed out of band or through an extension |
| Expected resolution | A client message on the same taskId |
A credential delivered to the agent, usually out of band; the client may also send messages |
| Can the agent resume on its own? | The client’s next message supplies the input | Yes, as soon as the credential arrives |
Both states are non-terminal. A blocking SendMessage, which is the default, returns as soon as the task reaches either one (section 3.2.2), so a client never waits on itself. A client can leave either state by canceling.
Continuing a task: the identifier rules
Section 3.4 sets these rules for messages that continue work.
| Client sends | Agent behavior | Section |
|---|---|---|
A taskId that does not exist or is not accessible |
Must return TaskNotFoundError (-32001) |
3.4.2 |
A taskId with no contextId |
Must infer the contextId from the task |
3.4.3 |
A taskId plus a contextId that differs from the task’s |
Must reject the message | 3.4.3 |
A client-chosen contextId the agent cannot accept |
Must reject the request and must not generate a replacement | 3.4.1 |
A contextId with no taskId |
Starts a new task in that conversation | 3.4.3 |
The taskId of a task in a terminal state |
Must return UnsupportedOperationError (-32004) |
3.1.1 |
A taskId the client invented for a new task |
Not supported; task IDs are server-generated | 3.4.2 |
The specification does not name an error code for a mismatched pair. It is a validation failure, and section 3.3.2 gives -32602 Invalid params as the JSON-RPC code for those, INVALID_ARGUMENT for gRPC and 400 Bad Request for HTTP. The live example below shows one.
Two more rules matter for clients. Server-generated contextId values should be treated as opaque, and a client should not send its own contextId unless it knows how the server will handle it. To tie a new task to earlier work, list the earlier tasks in referenceTaskIds.
Retries need care. Section 3.3.1 says SendMessage may be idempotent and that agents may use messageId to detect duplicates. Reusing the same messageId when you retry a continuation gives the agent a chance to drop the duplicate, but nothing guarantees it will.
Input required in practice
The agent puts its question in status.message. The specification separates this kind of communication from results: status messages ask and explain, and artifacts carry outputs (section 3.7). The same section warns that messages are not a reliable delivery channel. The agent decides which messages it keeps in history, and a client that reconnects a stream may miss status updates. Read the question from the task’s current status, which GetTask always returns. history may not hold it.
A question can ask for free text or for structured data. The protocol has no field for attaching a schema to the question. Agents describe the expected shape in the question text or in the skill description on their Agent Card, and an extension could make it formal.
What a client should show
The specification does not define a user interface. These practices follow from what it does define:
- Who is asking. Show the remote agent’s name and provider from its Agent Card. Both are claims made by whoever published the card.
- What is asked. Show
status.messageas the remote agent’s words. It is untrusted input from another party, so it must not steer your agent’s tools or release data on its own authority. - What your agent would send. If your agent can answer from data it already holds, decide by policy whether it may answer without asking the person. Contact details, account numbers and approvals usually need the person.
- The ways out. Offer to answer, to decline in a message, or to cancel the task.
- The cost of waiting. The task stays open until someone acts or the agent expires it.
Auth required
Section 7.6 covers authorization an agent needs in the middle of a task. Its examples are an agent that needs an OAuth access token to call an API or another agent, and an action that needs a person’s approval before it runs.
What the agent does (7.6.1)
- Tracks the operation as a
Taskand moves it toTASK_STATE_AUTH_REQUIRED. - Explains the required authorization in a status message, unless the details were negotiated out of band or through an extension.
- Arranges to receive the credential out of band, unless an in-band mechanism was negotiated.
- Keeps active response streams open when the credential arrives out of band. It may continue as soon as it has the credential, with no follow-up message from the client.
- Keeps accepting messages on the task, so the client can negotiate, correct or reject the request.
What the client does (7.6.2)
A client can answer the task with a message, ask another person, agent or service to fulfil the request, or fulfil it directly through an out-of-band or extension-defined channel. A client that is itself an agent working on a task can pass the request upstream by moving its own task to AUTH_REQUIRED. That forms a chain of interrupted tasks.
Because the agent can resume without telling the client first, a client with no open stream could miss the change. The specification says it should subscribe to the task, register a webhook if the agent supports push notifications, or poll with GetTask. See streaming and push notifications for all three.
Credentials inside the protocol (7.6.3)
Out of band over HTTPS is the default and the recommendation. In-band exchange needs prior agreement, because a credential passed through a chain of agents is visible to every agent in it. If you pass credentials in band, bind them to the agent that asked so no other agent can use them, and encrypt sensitive ones so only that agent can read them.
This is separate from request authentication. Every request is authenticated with the schemes the Agent Card declares in securitySchemes (sections 7.3 and 7.4). AUTH_REQUIRED covers authorization that one step of one task needs.
Illustrative: an agent pauses a refund until the account holder approves it.
{
"id": "task-7c1e",
"contextId": "ctx-40d2",
"status": {
"state": "TASK_STATE_AUTH_REQUIRED",
"timestamp": "2026-09-26T15:04:05.000Z",
"message": {
"messageId": "msg-a1",
"taskId": "task-7c1e",
"contextId": "ctx-40d2",
"role": "ROLE_AGENT",
"parts": [{ "text": "Refunds above CAD 200 need approval from the account holder. We sent an approval request to the address on file." }]
}
}
}
What section 7.6.4 leaves undefined
Section 7.6.4 says the protocol does not define the scope, representation, validity or revocation of the authorization decision or credential. It adds three rules:
- The state change alone must not be treated as authorization for any operation.
- The meaning of a credential must come from the agent’s implementation, the credential issuer or an A2A extension. An implementation that needs authorization for specific operations must define how each operation is identified and checked before it runs.
- A credential obtained during
AUTH_REQUIREDmust not be assumed to authorize later messages on the task, unless the implementation, issuer or extension says so.
Section 7.6.4 is on the specification’s main branch. It arrived through pull request #2081, merged on 30 July 2026, after the v1.0.1 release of 28 May 2026, whose text ends at section 7.6.3. The protocol version is still 1.0. Treat 7.6.4 as the working group’s current reading, and expect agents built against v1.0.1 not to cite it.
An implementation has to answer these questions itself:
| Question | Why it matters |
|---|---|
| Which operation does the approval cover? | Without a bound operation, an approval for one refund could be replayed for another |
| Which agent may use it? | Section 7.6.3 recommends binding it to the requesting agent |
| How long is it valid? | The protocol sets no expiry |
| How is it revoked? | The protocol defines no revocation |
| Where is it checked? | Section 7.6.4 puts the check on the implementation, before the operation runs |
One published answer is the experimental OID4VP In-Task Authorization extension in the a2aproject organization. An agent in AUTH_REQUIRED places an OpenID for Verifiable Presentations authorization request in the status message’s metadata, keyed by the extension URI, and the client’s wallet answers the verifier out of band. Emissar’s Mandate module proposes a scoped, revocable credential for the same gap, intended to be carried as an A2A extension. Its status is Spec in progress.
Timeouts, expiry and cancellation
The specification sets no timeout for an interrupted task. Agents may expire contexts or clean up old data and should document that policy (section 3.4.1). A purged task looks like any unknown task and returns TaskNotFoundError. A client continuing an old task should handle -32001 by starting over with a new message, listing the old task in referenceTaskIds if that helps.
Canceling works on interrupted tasks like any other non-terminal task. CancelTask returns the updated task, success is not guaranteed, and repeating the call has the same effect (sections 3.1.5 and 3.3.1). A task that has already ended returns TaskNotCancelableError (-32002). The agent can also end an interrupted task itself: TASK_STATE_REJECTED covers an agent that decides it can’t or won’t proceed after the task was created.
The one timeout the specification recommends is 10 to 30 seconds per webhook request for push notifications. That limit applies to delivery attempts. It says nothing about how long a task may wait.
Live example: an input-required signup
Emissar’s public agent at https://emissar.ai/a2a/v1 (JSON-RPC binding, A2A 1.0) has a request-early-access skill that returns TASK_STATE_INPUT_REQUIRED when the email address is missing. Its Agent Card declares streaming and push notifications as false, so clients follow tasks by polling. Its privacy policy says messages to the agent are deleted after 90 days, which is the kind of expiry policy section 3.4.1 asks agents to document. The calls below ran on 2026-09-26. IDs and timestamps are real, and responses are formatted for reading. The address is a documentation placeholder; the agent registers whatever address it receives.
1. Start the task
curl -s https://emissar.ai/a2a/v1 \
-H 'Content-Type: application/json' \
-H 'A2A-Version: 1.0' \
-d '{"jsonrpc": "2.0", "id": 1, "method": "SendMessage",
"params": {
"message": {"role": "ROLE_USER", "messageId": "smoke-test-docs-mt-1",
"parts": [{"text": "Please register Example Docs Co for Emissar early access."}]},
"configuration": {"historyLength": 0}}}'
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"task": {
"id": "68871248-f430-4096-99cd-a49d80c922f0",
"contextId": "df03d5f8-26ba-498f-96ea-c951d747bad1",
"status": {
"state": "TASK_STATE_INPUT_REQUIRED",
"timestamp": "2026-09-26T20:20:46.379Z",
"message": {
"role": "ROLE_AGENT",
"parts": [
{
"text": "Which email address should I register? Send it as text, or as a data part like {\"email\": \"name@company.com\"}. You can also include name, company, role, side, program and useCase."
}
],
"messageId": "6b043093-7da4-4efc-859e-e8d7aed268cd",
"taskId": "68871248-f430-4096-99cd-a49d80c922f0",
"contextId": "df03d5f8-26ba-498f-96ea-c951d747bad1"
}
},
"artifacts": [],
"metadata": {
"skill": "request-early-access"
}
}
}
}
The task stopped in TASK_STATE_INPUT_REQUIRED with the question in status.message. Setting historyLength to 0 left out the history field.
2. Send a contextId that doesn’t match
The next message carries the task’s taskId but the contextId "ctx-does-not-match" (messageId smoke-test-docs-mt-2):
{
"jsonrpc": "2.0",
"id": 2,
"error": {
"code": -32602,
"message": "Invalid parameters: message.contextId does not match the task's contextId",
"data": [
{
"@type": "type.googleapis.com/google.rpc.ErrorInfo",
"reason": "INVALID_PARAMS",
"domain": "emissar.ai"
}
]
}
}
The agent rejected the message, as section 3.4.3 requires. It reports standard JSON-RPC errors under its own domain and uses a2a-protocol.org for the A2A-specific range. The task is unchanged and still waiting.
3. Answer on the same task
This message sends only the taskId and gives the answer as a structured data part:
curl -s https://emissar.ai/a2a/v1 \
-H 'Content-Type: application/json' \
-H 'A2A-Version: 1.0' \
-d '{"jsonrpc": "2.0", "id": 3, "method": "SendMessage",
"params": {
"message": {"role": "ROLE_USER", "messageId": "smoke-test-docs-mt-3",
"taskId": "68871248-f430-4096-99cd-a49d80c922f0",
"parts": [{"data": {"email": "docs-example@example.com", "company": "Example Docs Co"},
"mediaType": "application/json"}]},
"configuration": {"historyLength": 0}}}'
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"task": {
"id": "68871248-f430-4096-99cd-a49d80c922f0",
"contextId": "df03d5f8-26ba-498f-96ea-c951d747bad1",
"status": {
"state": "TASK_STATE_COMPLETED",
"timestamp": "2026-09-26T20:20:55.008Z"
},
"artifacts": [
{
"artifactId": "59e9f011-abe1-404e-9124-44077d21cf00",
"name": "Registration",
"parts": [
{
"text": "Registered docs-example@example.com for early access. A person at Emissar will follow up by email. This registration arrived over A2A, which is exactly the kind of exchange Emissar is built for."
},
{
"data": {
"registered": true,
"email": "docs-example@example.com",
"program": "early_access"
},
"mediaType": "application/json"
}
]
}
],
"metadata": {
"skill": "request-early-access"
}
}
}
}
The agent inferred the contextId from the task, completed it, and returned the result as an artifact with a text part and a data part. The question is gone from status because the task no longer waits for anything.
4. Cancel an interrupted task
A second request without an email (messageId smoke-test-docs-mt-4) produced a new task in TASK_STATE_INPUT_REQUIRED. Canceling it with CancelTask and "params": {"id": "16924c7f-0267-4b42-9783-e2c1bd4bcfaf"} returned this (history omitted here):
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"id": "16924c7f-0267-4b42-9783-e2c1bd4bcfaf",
"contextId": "8ae0c4f0-1600-4eb6-a371-750709ff3d04",
"status": {
"state": "TASK_STATE_CANCELED",
"timestamp": "2026-09-26T20:21:02.880Z",
"message": {
"role": "ROLE_AGENT",
"parts": [
{
"text": "Canceled. Nothing was registered."
}
],
"messageId": "dc081799-a81b-42cd-9865-171cbe618b36",
"taskId": "16924c7f-0267-4b42-9783-e2c1bd4bcfaf",
"contextId": "8ae0c4f0-1600-4eb6-a371-750709ff3d04"
}
},
"artifacts": [],
"metadata": {
"skill": "request-early-access"
}
}
}
CancelTask returns the task itself, without the task wrapper that SendMessage uses. The task is now terminal, so any further message to it gets -32004.
Questions
- Which error should an agent return for a mismatched taskId and contextId?
- The specification says the agent must reject the message but does not name a code. It is a validation failure, which section 3.3.2 maps to -32602 Invalid params in JSON-RPC, INVALID_ARGUMENT in gRPC and 400 Bad Request over HTTP.
- Does an agent have to accept a contextId the client made up?
- No. Agents may accept client-provided contextId values. If an agent cannot accept one, it must return an error and must not substitute a new contextId of its own.
- Can the credential for TASK_STATE_AUTH_REQUIRED travel inside an A2A message?
- Only if that was negotiated out of band or through an extension. By default the agent arranges to receive credentials out of band, for example over HTTPS directly from the person or service that grants them.
- How long does an interrupted task wait?
- The protocol sets no limit. Agents may expire contexts and clean up tasks and should document that policy. After cleanup, the task ID returns TaskNotFoundError (-32001).
Sources
- A2A Protocol Specification (sections 3.1, 3.2.2, 3.3, 3.4, 3.7 and 7.6) (accessed )
- A2A Protocol Specification v1.0.1 (tagged release, ends at section 7.6.3) (accessed )
- A2A pull request #2081: clarify in-task authorization scope semantics (accessed )
- A2A protocol definition (a2a.proto): TaskState, Message, SendMessageConfiguration (accessed )
- A2A releases (v1.0.1, 2026-05-28) (accessed )
- OID4VP In-Task Authorization Extension (experimental, a2aproject) (accessed )
- Emissar Agent Card (live example agent) (accessed )
- Emissar privacy policy (retention of messages to the A2A agent) (accessed )
- Emissar: Mandate module (accessed )