A2A IDENTITY · INBOUND TOKEN POLICY

Agent identity: trust and audience boundaries

Eight agents call a payments agent with bearer tokens. Tune the receiver’s verification policy and see which forged, replayed or expired tokens get in.

Computed experiment · sixty inspection seconds

Your experiment

payments-agent receives eight requests. Three are legitimate, one from a caller whose clock runs 20 seconds ahead. The others carry an expired token, a token minted for the billing agent, a self-signed token, an edited token and an unsigned alg-none token. The opening policy verifies signatures with pinned keys but skips the audience and allows 120 seconds of clock leeway.

Play replays the computed run over sixty inspection seconds; Next event steps, Restart rewinds, and Inspection time scrubs. Any input change recomputes the run and rewinds it without autoplay.

Event trace

    Computed data

    Final metrics

    The checks are the receiving agent’s own policy: an A2A agent card declares the security schemes it accepts, and the protocol does not fix which claims are verified. Fictional tokens; times are relative to the receiver’s clock. No identity provider, network or JWT library is used.

    A receiver decides who is calling

    When an ADK Java agent serves A2A requests, its own code decides what a bearer token must prove before the executor runs. Signature chooses between verifying and merely decoding the claims. Algorithms either allows only RS256 and ES256 or trusts the alg named in the token header. Verification keys come from a pinned JWKS of the trusted issuer or from the jku URL inside the token. Require audience = payments rejects tokens minted for other agents. Clock leeway tolerates differences between the issuer’s clock and this one.

    The opening run: verified, still broken

    Signatures are checked with pinned keys and only allowed algorithms, so the self-signed token, the edited token and the alg-none token are rejected. But two bad tokens get in. Q2 expired 90 seconds ago, inside the 120-second leeway. Q3 was minted for the billing agent and replayed here, and nothing checks the audience. The three legitimate callers are accepted. A valid signature proves who issued a token, not that it was meant for you or still current.

    Closing the audience and time gaps

    Tick Require audience = payments and Q3 is rejected. Lower Clock leeway to 30 s: Q2 is now rejected as expired, and Q6, whose issuer’s clock runs 20 seconds ahead, is still accepted, so the boundary holds with three accepted and five rejected. At 0 s Q6 becomes a wrongly rejected legitimate caller; at 90 s Q2 gets back in. Leeway is a trade: just above the real clock skew, never minutes.

    Failure boundary: trusting the token about itself

    From the opening, choose Whatever the token header says: Q7, an unsigned token claiming alg none, is accepted. Fetched from the token’s jku URL lets Q4 present its own keys and pass, because the token chose who vouches for it. Decode claims only accepts five bad tokens, including the edited one. Even with the audience and 30 s leeway set, those two options reopen Q4 and Q7. Every check must use information the receiver controls: its allow-listed algorithms, its pinned keys, its own name and its own clock.

    Reading the run and its limits

    Play replays the requests two at a time and the outcome over sixty inspection seconds; the table gives each decision and whether it was correct. Next event, Restart, Speed and Inspection time control the replay. The tokens are fictional and the decisions follow the rules described, not a specific JWT library. Authentication is only the first step; a caller that passes still needs authorization for the specific skill and tenant it asks for.