Overview

ACK-ID is a protocol built on W3C Standards designed to bring verifiable, secure, compliant identity, reputation, and service discovery to agents.

A2A (Agent2Agent) is a protocol developed by Google to standardize communication between multiple agents.

This interactive command-line demo showcases how two A2A-compatible agents can use ACK-ID to verify each other’s identity and trust that they are communicating with the expected agent.

Getting Started

Before running this demo, follow the Quickstart Guide to ensure you are set up properly.

Running the Demo

You can use the demo by running the following command from the root of this repository:

pnpm run demo:identity-a2a

Alternatively, from within the demo directory (./demos/identity-a2a):

pnpm run demo

Demo Walkthrough

This demo showcases a mutual authentication flow between a Bank Customer Agent and a Bank Teller Agent using ACK-ID DIDs and JWTs exchanged within A2A message bodies. The demo walks through the following authentication flow:

1

Initial Contact - Customer Agent Initiates

The Customer Agent sends an authentication request as an A2A message containing a signed JWT with a nonce:

{
  "role": "user",
  "kind": "message",
  "messageId": "f1f54f9d-6db2-4d78-8b38-4e50d77c8b19",
  "parts": [
    {
      "type": "data",
      "data": {
        "jwt": "<signed-JWT-from-customer>"
      }
    }
  ]
}

The JWT payload includes:

{
  "iss": "did:web:customer.example.com",
  "aud": "did:web:bank.example.com",
  "nonce": "c-128bit-random",
  "iat": 1718476800,
  "jti": "0e94d7ec-...",
  "exp": 1718477100
}
2

Bank Teller Agent Response

The Bank Teller Agent verifies the customer’s JWT signature and responds with its own signed JWT, including both the customer’s nonce and a new server nonce:

{
  "role": "agent",
  "kind": "message",
  "messageId": "f1f54f9d-6db2-4d78-8b38-4e50d77c8b19",
  "parts": [
    {
      "type": "data",
      "data": {
        "jwt": "<signed-JWT-from-bank>"
      }
    }
  ]
}

The Bank’s JWT payload:

{
  "iss": "did:web:bank.example.com",
  "aud": "did:web:customer.example.com",
  "nonce": "c-128bit-random",
  "replyNonce": "b-128bit-random",
  "jti": "1f85c8fa-...",
  "iat": 1718476805,
  "exp": 1718477105
}
3

Subsequent Communications

After successful mutual authentication, all subsequent messages include a signature in the metadata:

{
  "role": "user",
  "kind": "message",
  "messageId": "89f2e11b-5b0a-4c3b-b49d-14628e5d30fb",
  "parts": [
    {
      "type": "text",
      "text": "Please check the balance for account #12345"
    }
  ],
  "metadata": {
    "sig": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9...Q"
  }
}

The signature is a JWT with the payload:

{
  "message": <the-message-object-without-metadata>
}

with aud and iss set for the counterparty and sender’s DID, respectively.

Security Benefits

This authentication flow provides several security advantages:

  • Mutual Authentication: Both parties prove their identity through cryptographic signatures.
  • Replay Attack Prevention: Nonces and JWT IDs ensure messages cannot be replayed.
  • Man-in-the-Middle (MITM) Protection: The aud and iss fields are pinned in the JWTs, preventing tampering. An attacker cannot modify requests or responses without invalidating the signatures.
  • Short-lived Tokens: 5-minute expiry limits the window for potential attacks.
  • Verifiable Identity: DID-based authentication ensures cryptographic proof of identity.

Further Exploration