Skip to content

Latest commit

 

History

History
115 lines (89 loc) · 3.41 KB

File metadata and controls

115 lines (89 loc) · 3.41 KB

Resource-Managed Access

Live demo | Access Mode Comparison

Overview

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).

Sequence Diagram

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
Loading

Code Example

Client-Side (Agent)

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 request
Manual 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
}

Server-Side (IOpaqueTokenStore)

// Resource issues opaque tokens after interaction completes
builder.Services.AddSingleton<IOpaqueTokenStore>(new InMemoryOpaqueTokenStore());

DI Registration

Agent-Side

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);
});

Resource-Side

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.

Error Scenarios

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

Further Reading