feat: live interop testing with adaptive signing and typed token-exchange errors#27
Merged
Conversation
- 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).
There was a problem hiding this comment.
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
AAuthTokenExchangeExceptionand token-endpoint error parsing inTokenExchangeClient(with newuser_unreachablesupport). - Add adaptive signature components: per-request additional covered components +
Signature-Error: invalid_input; required_input="..."learning/caching and single retry. - Add
LiveWhoAmITestsample + 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
…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).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the protocol gaps surfaced by running the SDK against the live
whoami.aauth.devresource server andperson.hello.coopPerson Server.Implements Phases 4-6 of the live-interop-testing plan and adds a runnable
live interop sample.
SDK changes
AAuthTokenExchangeException(
ErrorCode,ErrorDescription,StatusCode,IsTerminal).TokenExchangeClientparses{error, error_description}from PStoken-endpoint responses and throws typed, falling back to
HttpRequestExceptionfor non-protocol failures.AAuthSigningHandlerappends extracovered components additively (the RFC 9421 base set is never dropped).
ChallengeHandlerlearns the required set from a401withSignature-Error: invalid_input+required_input, caches it per origin,and retries once. Seeded via
ChallengeHandlingOptions.AdditionalSignatureComponents.SignatureError.ParseRequiredInputfor therequired_inputparameter.user_unreachableis now an explicit terminal (400)TokenErrorCode.Samples & tooling
over a
cloudflaredquick tunnel. Verified live (all modes pass).cloudflaredinstalled via the dev container post-create script.make livetarget andsamples/README.mdcoverage added.Docs
Fixed verified inaccuracies found during documentation validation:
MetadataCacheTtl/JwksCacheTtl+JwksMinRefreshInterval).Signature-Errorwire-code table.AAuth-Requirementchallenge header (wasWWW-Authenticate).ExchangeAsyncrequiredonInteractionRequiredparameter.TokenErrorResponse,PollingErrorException).Testing
401+Accept-Signature),Mode 2a (
200agent 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.
AAuthSigningHandlernow computesContent-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.SeedAdditionalComponentsmerges caller-setAdditionalComponentsKeyvalues with the seeded/learned set rather than overwriting them.CloneAsynccopiesHttpRequestMessage.Options, so request-scoped state (Polly context, telemetry, caller key, additional components) survives the adaptive retry.TokenExchangeRequestoptions object (H1): the source-breaking positionalExchangeAsyncoverload was replaced withExchangeAsync(personServer, resourceToken, TokenExchangeRequest options, CancellationToken); the 3-arg convenience overload is retained andCancellationTokenstays last. The fluent builder surface (AAuthClientBuilder,ChallengeHandlingOptions) is unchanged.DeferredPollertimeout (M3): corrected the misleadingInfiniteTimeSpancomment and documented (in<remarks>and the docs) that a directly constructed poller using long-poll must setHttpClient.Timeoutgreater thanPreferWaitSeconds.AddOrUpdatefor learned components; robustrequired_inputparsing (;-split, exact name match);interaction_requiredterminality note;LiveWhoAmITesttry/finally teardown with process disposal; restored a cosmetic blank line inpost-create.sh.Docs & samples
A dedicated docs/samples update accompanied each fix:
ExchangeAsyncsnippets incall-chaining.mdanddeferred-consent.mdmoved to theTokenExchangeRequestobject form; long-poll timeout notes added todeferred-consent.mdandinteraction-chaining.md;overview.mdanderror-handling.mdupdated for the Content-Digest behavior; a clarifying comment added in GuidedTour.Testing
ParseRequiredInput).make whoami/ap/ps):hwk,jwks_uri,jkt-jwt, andjwtall return200.