Skip to content

feat: live interop testing with adaptive signing and typed token-exchange errors#27

Merged
dasiths merged 4 commits into
mainfrom
feat/live-interop-testing
May 31, 2026
Merged

feat: live interop testing with adaptive signing and typed token-exchange errors#27
dasiths merged 4 commits into
mainfrom
feat/live-interop-testing

Conversation

@dasiths
Copy link
Copy Markdown
Collaborator

@dasiths dasiths commented May 30, 2026

Summary

Closes the protocol gaps surfaced by running the SDK against the live
whoami.aauth.dev resource server and person.hello.coop Person Server.
Implements Phases 4-6 of the live-interop-testing plan and adds a runnable
live interop sample.

SDK changes

  • Typed token-exchange errors: new AAuthTokenExchangeException
    (ErrorCode, ErrorDescription, StatusCode, IsTerminal).
    TokenExchangeClient parses {error, error_description} from PS
    token-endpoint responses and throws typed, falling back to
    HttpRequestException for non-protocol failures.
  • Adaptive signature components: AAuthSigningHandler appends extra
    covered components additively (the RFC 9421 base set is never dropped).
    ChallengeHandler learns the required set from a 401 with
    Signature-Error: invalid_input + required_input, caches it per origin,
    and retries once. Seeded via ChallengeHandlingOptions.AdditionalSignatureComponents.
  • SignatureError.ParseRequiredInput for the required_input parameter.
  • user_unreachable is now an explicit terminal (400) TokenErrorCode.

Samples & tooling

  • LiveWhoAmITest: end-to-end sample exercising all three protocol modes
    over a cloudflared quick tunnel. Verified live (all modes pass).
  • cloudflared installed via the dev container post-create script.
  • make live target and samples/README.md coverage added.

Docs

Fixed verified inaccuracies found during documentation validation:

  • Discovery cache options (MetadataCacheTtl/JwksCacheTtl + JwksMinRefreshInterval).
  • Complete Signature-Error wire-code table.
  • AAuth-Requirement challenge header (was WWW-Authenticate).
  • ExchangeAsync required onInteractionRequired parameter.
  • Error type names (TokenErrorResponse, PollingErrorException).
  • New adaptive-signing guide.

Testing

  • 320 unit + 342 conformance tests pass.
  • Full solution builds clean (0 warnings / 0 errors).
  • LiveWhoAmITest run against the live servers: Mode 1 (401 + Accept-Signature),
    Mode 2a (200 agent identity), Mode 2b (401 + AAuth-Requirement),
    Mode 3 (full three-party flow returning identity claims).

Update: PR #27 review remediation (Phase 7)

Addressed all four inline review comments plus internal review findings. Backward compatibility was intentionally not retained for the pre-release token-exchange API; the positional overload was replaced outright.

  • Content-Digest auto-computed (H2): AAuthSigningHandler now computes Content-Digest (sha-256) from the request body when a resource requires it as an additional covered component, instead of throwing during adaptive retry. The throw is reserved for components that cannot be auto-computed, and now names the origin.
  • Caller component merge (M1): SeedAdditionalComponents merges caller-set AdditionalComponentsKey values with the seeded/learned set rather than overwriting them.
  • Options preserved on retry (M2): CloneAsync copies HttpRequestMessage.Options, so request-scoped state (Polly context, telemetry, caller key, additional components) survives the adaptive retry.
  • TokenExchangeRequest options object (H1): the source-breaking positional ExchangeAsync overload was replaced with ExchangeAsync(personServer, resourceToken, TokenExchangeRequest options, CancellationToken); the 3-arg convenience overload is retained and CancellationToken stays last. The fluent builder surface (AAuthClientBuilder, ChallengeHandlingOptions) is unchanged.
  • DeferredPoller timeout (M3): corrected the misleading InfiniteTimeSpan comment and documented (in <remarks> and the docs) that a directly constructed poller using long-poll must set HttpClient.Timeout greater than PreferWaitSeconds.
  • Low-severity cleanups (L1-L5): AddOrUpdate for learned components; robust required_input parsing (;-split, exact name match); interaction_required terminality note; LiveWhoAmITest try/finally teardown with process disposal; restored a cosmetic blank line in post-create.sh.

Docs & samples

A dedicated docs/samples update accompanied each fix: ExchangeAsync snippets in call-chaining.md and deferred-consent.md moved to the TokenExchangeRequest object form; long-poll timeout notes added to deferred-consent.md and interaction-chaining.md; overview.md and error-handling.md updated for the Content-Digest behavior; a clarifying comment added in GuidedTour.

Testing

  • 325 unit + 345 conformance tests pass (added coverage for Content-Digest, caller-merge, option preservation, learned-component persistence, and ParseRequiredInput).
  • Full solution builds clean (0 warnings / 0 errors).
  • Live interop run re-verified: all three modes pass, returning real identity claims in Mode 3.
  • AgentConsole permutations verified against the local mock stack via the Makefile (make whoami/ap/ps): hwk, jwks_uri, jkt-jwt, and jwt all return 200.

dasiths added 3 commits May 28, 2026 17:25
- Add LiveWhoAmITest sample demonstrating all 4 protocol modes against
  whoami.aauth.dev and person.hello.coop
- Fix TokenExchangeClient: send capabilities in POST body when
  onInteractionRequired is non-null (Gap A - PS requires this)
- Fix DeferredPoller: per-request CTS to prevent HttpClient.Timeout
  from killing long-poll requests (Gap G)
- Add research document with spec-referenced gap analysis (A-J)
- Add implementation plan with gap register
…d spec changes for capabilities, user_unreachable, and prompt parameters
Implements Phases 4-6 of the live-interop-testing plan, closing the
remaining protocol gaps surfaced when running against the live
whoami.aauth.dev resource and person.hello.coop Person Server.

SDK changes:
- Add AAuthTokenExchangeException for structured PS token-endpoint errors
  (ErrorCode, ErrorDescription, StatusCode, IsTerminal); TokenExchangeClient
  parses {error, error_description} and throws typed, falling back to
  HttpRequestException.
- Add adaptive signature components: AAuthSigningHandler appends extra
  covered components additively (never dropping the base set), and
  ChallengeHandler learns required components from a 401 invalid_input
  + required_input response, caches them per origin, and retries once.
  Seeded via ChallengeHandlingOptions.AdditionalSignatureComponents.
- Add SignatureError.ParseRequiredInput for the required_input parameter.
- Make user_unreachable explicit in TokenErrorCode (terminal 400).

Samples and tooling:
- LiveWhoAmITest now reports terminal token-exchange failures via the
  typed AAuthTokenExchangeException.
- Install cloudflared in the dev container post-create script and add a
  `make live` target plus samples/README coverage for LiveWhoAmITest.

Docs:
- Fix verified inaccuracies found by documentation validation: discovery
  cache option names (MetadataCacheTtl/JwksCacheTtl + JwksMinRefreshInterval),
  full Signature-Error wire-code table, AAuth-Requirement challenge header,
  ExchangeAsync required parameter, error type names, and the adaptive
  signing guide.

Tests: 320 unit + 342 conformance pass; LiveWhoAmITest verified against
the live servers (all three protocol modes).
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements live interop learnings from running the SDK against deployed AAuth servers by adding typed PS token-exchange errors, adaptive/additive HTTP signature coverage, and a runnable live interop sample (plus supporting docs/tests).

Changes:

  • Add AAuthTokenExchangeException and token-endpoint error parsing in TokenExchangeClient (with new user_unreachable support).
  • Add adaptive signature components: per-request additional covered components + Signature-Error: invalid_input; required_input="..." learning/caching and single retry.
  • Add LiveWhoAmITest sample + Make/devcontainer tooling and update documentation to reflect the updated SDK surface/behavior.
Show a summary per file
File Description
tests/AAuth.Tests/HttpSig/AAuthSigningHandlerTests.cs Adds regression tests for additive signature component coverage and validation.
tests/AAuth.Tests/Agent/DeferredPollerTests.cs Adds timeout-budget regression test for long Retry-After handling.
tests/AAuth.Tests/Agent/ChallengeHandlerTests.cs Adds tests for capabilities/prompt body fields, typed exchange errors, and adaptive signing learning/cache behavior.
tests/AAuth.Conformance/Errors/TokenErrorTests.cs Extends conformance to cover user_unreachable parsing/terminal classification.
src/AAuth/Server/CallChainingHandler.cs Updates call to ExchangeAsync to use named cancellationToken.
src/AAuth/HttpSig/ChallengeHandlingOptions.cs Adds Capabilities, Prompt, and AdditionalSignatureComponents configuration options.
src/AAuth/HttpSig/AAuthSigningHandler.cs Supports per-request additional covered components via HttpRequestMessage.Options.
src/AAuth/HttpSig/AAuthClientBuilder.cs Sets exchange HttpClient timeout to infinite; threads new challenge-handling options into ChallengeHandler.
src/AAuth/Errors/TokenError.cs Adds UserUnreachable error code mapping/parsing.
src/AAuth/Errors/SignatureError.cs Adds ParseRequiredInput helper for required_input.
src/AAuth/Errors/AAuthTokenExchangeException.cs Introduces typed token-exchange exception with terminal/transient classification.
src/AAuth/Agent/TokenExchangeClient.cs Adds capabilities/prompt request-body fields and throws typed exceptions for structured non-2xx error bodies.
src/AAuth/Agent/DeferredPoller.cs Ensures sleep is clamped to remaining budget; adds note about long-poll timeouts.
src/AAuth/Agent/ChallengeHandler.cs Adds adaptive signing handshake (seed/learn/cache/one retry) and passes capabilities/prompt to exchange.
samples/README.md Documents the new live interop sample and adds make live.
samples/LiveWhoAmITest/Program.cs Adds runnable live interop sample exercising modes 1–3 over a quick tunnel.
samples/LiveWhoAmITest/LiveWhoAmITest.csproj Adds new sample project.
samples/GuidedTour/CodeSnippets.cs Updates snippet to include required KeyId.
Makefile Adds live target.
docs/workflows/call-chaining.md Fixes snippet to include required onInteractionRequired arg.
docs/signing-modes/overview.md Documents adaptive signature components behavior and seeding.
docs/server/verification-middleware.md Corrects/expands Signature-Error wire-code table.
docs/server/token-issuance.md Updates challenge emission to ChallengeAAuth / AAuth-Requirement.
docs/reference/dependency-injection.md Updates discovery cache option names/defaults.
docs/reference/configuration.md Updates discovery cache option names/defaults and expands options tables.
docs/README.md Fixes error type names and lists new exception type.
docs/advanced/error-handling.md Documents typed token-exchange errors and adaptive retry on invalid_input.
AAuth.slnx Includes new sample project.
aauth-spec/upcoming-changes-02.md Adds tracked upcoming -02 spec clarifications used by this PR.
.devcontainer/post-create.sh Installs cloudflared for the live sample.
.agent/plans/2026-05-28-live-interop-testing/research.md Adds research document for the live interop initiative.
.agent/plans/2026-05-28-live-interop-testing/implementation-plan.md Adds implementation plan and phase completion tracking for the initiative.

Copilot's findings

  • Files reviewed: 32/32 changed files
  • Comments generated: 4

Comment thread src/AAuth/Agent/ChallengeHandler.cs
Comment thread src/AAuth/Agent/ChallengeHandler.cs
Comment thread src/AAuth/Agent/TokenExchangeClient.cs
Comment thread src/AAuth/Agent/DeferredPoller.cs Outdated
…change

Remediate the four PR review comments plus internal review findings.

- Auto-compute Content-Digest in AAuthSigningHandler when a resource requires
  it as an additional covered component, instead of throwing (H2).
- Merge caller-set additional components in SeedAdditionalComponents rather
  than clobbering request.Options, and copy HttpRequestMessage.Options in
  CloneAsync so request-scoped state survives the adaptive retry (M1, M2).
- Replace the source-breaking positional ExchangeAsync overload with a
  TokenExchangeRequest options object (H1).
- Reword the misleading DeferredPoller InfiniteTimeSpan comment and document
  the HttpClient timeout requirement for directly constructed pollers (M3).
- Low-severity cleanups: AddOrUpdate for learned components, robust
  required_input parsing, interaction_required terminality note, LiveWhoAmITest
  try/finally teardown, post-create.sh blank line (L1-L5).

Update docs, samples, and guided-tour snippets to the new surface; add unit and
conformance coverage. All modes verified via the live interop run and the local
AgentConsole permutations (hwk, jwks_uri, jkt-jwt, jwt).
@dasiths dasiths merged commit 0caef09 into main May 31, 2026
1 check passed
@dasiths dasiths deleted the feat/live-interop-testing branch May 31, 2026 14:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants