The resource handles authorization itself — via user interaction, existing OAuth/OIDC, or internal policy. After authorization, the resource returns an opaque access token for subsequent calls. Two-party only (agent + resource).
sequenceDiagram
participant Agent
participant Resource
participant User
Agent->>Resource: GET /data (signed)
Resource-->>Agent: 202 + AAuth-Requirement: interaction (url, code)
User->>Resource: Completes interaction at resource's page
Agent->>Resource: GET /pending/<id> (poll)
Resource-->>Agent: 200 + AAuth-Access: <opaque-token>
Agent->>Resource: GET /data (signed + Authorization: AAuth <token>)
Resource-->>Agent: 200 OK
Use WithInteractionHandling() to automatically handle 202 + interaction requirements:
using var client = new AAuthClientBuilder(key)
.UseHwk()
.WithInteractionHandling(options =>
{
options.OnInteractionRequired = async (url, code, ct) =>
{
Console.WriteLine($"Approve at: {url}?code={code}");
};
})
.Build();
var response = await client.GetAsync("https://resource.example/data");
// Interaction handling polls until the resource resolves the requestManual Handling
var response = await client.GetAsync("https://resource.example/data");
if (response.StatusCode == HttpStatusCode.Accepted)
{
// Parse AAuth-Requirement header for interaction URL
var requirement = AAuthRequirementHeader.Parse(
response.Headers.GetValues("AAuth-Requirement").First());
// Present interaction URL to user
// Poll pending URL until resolved
}// Resource issues opaque tokens after interaction completes
builder.Services.AddSingleton<IOpaqueTokenStore>(new InMemoryOpaqueTokenStore());var key = await keyStore.LoadAsync(configuration["AAuth:LocalKeyHandle"]!);
builder.Services.AddAAuthAgent("resource-managed", options =>
{
options.Key = key!;
// No TokenRefresher needed — HWK mode (pseudonymous)
options.OnResourceInteraction = async (url, code, ct) =>
{
await notifier.SendAsync($"Approve at: {url}?code={code}", ct);
};
options.PollingTimeout = TimeSpan.FromMinutes(3);
});builder.Services.AddAAuthResource(options =>
{
options.Issuer = "https://resource.example";
options.SigningKeys = new() { ["key-1"] = resourceKey };
});
builder.Services.AddSingleton<IOpaqueTokenStore>(new InMemoryOpaqueTokenStore());See Dependency Injection for full reference.
| Status | Header | Cause |
|---|---|---|
| 401 | Signature-Error: invalid_signature |
Signature doesn't verify |
| 202 | AAuth-Requirement: interaction |
Authorization pending — user interaction required |
| 403 | (none) | Interaction completed but access denied by resource policy |