This sample demonstrates how to implement Bearer Token authentication. It shows how to intercept requests, validate tokens, extract the user generated by the authentication and pass it to the context.
index.ts: generates anAgentCardthat requires Bearer authentication for incoming requests and starts the server with the authentication middleware and user builder.authentication_middleware.ts: creates the middleware responsible for authentication. It uses Passport to support Bearer token authorization and populates theuserparameter in the Request object with the plain extracted object.user_builder.ts: defines the callback for the user extraction. It expects the user object (populated by the middleware) to contain specific values (email,userName,role) which are used to build theCustomUserobject.agent_executor.ts: creates a simple agent executor that checks the authentication status of the user object present in the context, which is expected to be an instance ofCustomUserin case of successful authentication, and sends back the content.
npm run agents:authentication-agentThe agent will start on http://localhost:41241.
The middleware uses HS256 with the symmetric secret
a2a-secret-for-authentication-sample (see authentication_middleware.ts:9).
For a successful authentication the JWT payload MUST contain email,
userName, and role.
You can generate a token with the jwt.io encoder, or locally:
node -e "
const crypto = require('node:crypto');
const header = Buffer.from(JSON.stringify({alg:'HS256',typ:'JWT'})).toString('base64url');
const payload = Buffer.from(JSON.stringify({userName:'alice',email:'alice@example.com',role:'admin'})).toString('base64url');
const sig = crypto.createHmac('sha256','a2a-secret-for-authentication-sample').update(header+'.'+payload).digest('base64url');
console.log(header+'.'+payload+'.'+sig);
"The A2A-Version header is required: when it is omitted the JSON-RPC binding
falls back to 0.3, and the server (which advertises only A2A_PROTOCOL_VERSION,
currently 1.0) rejects the request with VERSION_NOT_SUPPORTED.
curl -X POST http://localhost:41241/ \
-H "Authorization: Bearer <jwt-token>" \
-H "Content-Type: application/json" \
-H "A2A-Version: 1.0" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "SendMessage",
"params": {
"message": {
"messageId": "9229e770-767c-417b-a0b0-f0741243c589",
"role": "ROLE_USER",
"parts": [
{ "text": "Hello, who am I?", "mediaType": "text/plain" }
]
}
}
}'{
"jsonrpc": "2.0",
"id": 1,
"result": {
"message": {
"messageId": "<server-generated-uuid>",
"contextId": "<server-generated-uuid>",
"taskId": "<server-generated-uuid>",
"role": "ROLE_AGENT",
"parts": [
{
"text": "The request is coming from the authenticated user alice, with email alice@example.com and role admin.",
"mediaType": "text/plain"
}
],
"metadata": {}
}
}
}{
"jsonrpc": "2.0",
"id": 1,
"result": {
"message": {
"messageId": "<server-generated-uuid>",
"contextId": "<server-generated-uuid>",
"taskId": "<server-generated-uuid>",
"role": "ROLE_AGENT",
"parts": [
{
"text": "The request is not coming from an authenticated user.",
"mediaType": "text/plain"
}
],
"metadata": {}
}
}
}