Agent Token (sig=jwt)

June 3, 2026 · View on GitHub

Overview

The agent presents its full agent token inline. The resource (or Person Server) learns the agent's identity, issuer, and Person Server URL. See federated demo. Required for all Person Server flows.

When to Use

  • Three-party flows (PS-asserted, federated) — REQUIRED by spec
  • When the resource needs to discover the agent's Person Server (from the ps claim)
  • When the resource needs verified agent identity with issuer attestation

Prerequisite: Agent must have an aa-agent+jwt — either self-issued (hosted services that publish their own JWKS) or obtained from an Agent Provider (CLI/desktop agents that enrol).

Code Example

Hosted service (self-issued):

using AAuth.Crypto;
using AAuth;

var key = AAuthKey.Generate();

using var client = AAuthClientBuilder.SelfIssuing(key)
    .As("https://my-service.example", "aauth:my-service@my-service.example")
    .WithKid("svc-key-1")
    .WithPersonServer("https://ps.example")
    .WithChallengeHandling()
    .Build();

var response = await client.GetAsync("https://resource.example/data");
Advanced: Custom Token Building

For scenarios requiring additional claims, custom lifetimes, or non-standard flows, use the full AgentTokenBuilder via WithTokenRefresh:

using var client = new AAuthClientBuilder(key)
    .WithTokenRefresh((ctx, ct) => Task.FromResult(new AgentTokenBuilder
    {
        Issuer = "https://my-service.example",
        Subject = "aauth:my-service@my-service.example",
        KeyId = "svc-key-1",
        Key = key,
        PersonServer = "https://ps.example",
        AdditionalClaims = new Dictionary<string, JsonNode?>
        {
            ["attestation"] = "platform-verified",
        },
    }.Build()))
    .WithChallengeHandling("https://ps.example")
    .Build();

CLI/Desktop agent (AP-enrolled):

using AAuth.Agent;
using AAuth.Crypto;
using AAuth;

var keyStore = FileKeyStore.Default();
var key = await keyStore.LoadAsync(configuration["AAuth:LocalKeyHandle"]!);
var apRefreshEndpoint = configuration["AAuth:ApRefreshEndpoint"]!;

using var client = AAuthClientBuilder.Enrolled(key!)
    .RefreshingFrom(apRefreshEndpoint, configuration["AAuth:LocalKeyHandle"]!)
    .WithKeyStore(keyStore)
    .WithChallengeHandling("https://ps.example")
    .Build();

var response = await client.GetAsync("https://resource.example/data");
Manual Setup
var provider = new JwtSignatureKeyProvider(() => agentToken);
var handler = new AAuthSigningHandler(key, provider)
{
    InnerHandler = new HttpClientHandler()
};
using var client = new HttpClient(handler);

What the Resource Sees

  • Signature-Key: sig=jwt;jwt="eyJhbGciOi..."
  • Resource decodes the JWT: finds iss (agent's own URL or AP), sub (agent ID), cnf.jwk (bound key), optionally ps (Person Server URL)
  • Resource verifies: JWT signature (against issuer's JWKS via {iss}/.well-known/aauth-agent.json) + request signature (against cnf.jwk)

Verification

When the resource sees a ps claim, it can issue a resource token challenging the agent to get authorization from that PS. This is the entry point to PS-asserted and federated access.

Further Reading