Both decisions are signed: a Confirm carries
verdict: "approve" and a Deny carries verdict: "denied". An Expired or cancelled proposal produces no proof at all. Absence of a proof is never permission.Token format
Header:
The proof carries no personal data and does not include the Adaptive Card body.
Public keys
alg: "ES256", use: "sig", and a kid. It is served with a 5-minute cache lifetime, so cache it for 5 minutes and refetch when you meet an unknown kid. The same key set signs BotShield Gate attestation tokens.
Verify before you execute
Verification is local. There is no BotShield endpoint to call and nothing to trust except the signature. Installjose and verify:
Find your agent’s id
aud is the Agent ID: the UUID BotShield assigned to your agent, not its name. Copy it from the BotShield Console:
- Go to Agents Ask → Trusted Agents and select the environment with the Development | Production toggle.
- Find the agent’s row. The Agent ID is shown under the agent name.
- Click the copy button next to it.
BOTSHIELD_AGENT_ID), and pin audience to it. Treat it as configuration, not as a value you read from the token or from the agent at run time: the check is only worth something when the expected audience comes from you.
- A development agent and a production agent have different Agent IDs, so configure each environment with its own.
- The Agent ID stays the same when you rotate the agent’s key. A proof issued before a rotation still verifies against the same audience.
- An agent you register after revoking an old one has a new Agent ID, even if it reuses the name. Update the audience when you replace an agent.
agent_id in every agents_ask.card.proposed payload and as metadata.agent_id in every agents_ask.resolution.* payload. Use it there to tell which agent an event belongs to.
How the proof reaches you
The same token is delivered two ways. Verify it the same way on both, and make execution idempotent onjti, because you may receive it twice.
- Poll check-status
- Webhooks
GET /agentlink/check-status returns the token as resolution_jwt once the status is approved or denied. It is null for queued, expired, and cancelled.Outcomes at a glance
Keep the proof
Store the token with the record of the action it authorized. It is a self-contained, independently verifiable record that a verified human confirmed that exact request, which is useful for disputes and audits. Verify it when it arrives and record the result and the time next to it: afterexp the token no longer passes a standard JWT verification.
Next steps
Propose an action
Where
request_id, verdict, and resolution_jwt come from.Webhook events
Full payloads for the
agents_ask.* events.Privacy boundary
Why
sub is an opaque, per-agent id.agentgateway
Use BotShield with agentgateway in front of your agent’s tools.
