Phase 2: Resource server, signature verification, and three-party flow#6
Merged
Conversation
- Add AAuthUrl.IsHttpsOrLoopback helper; route all token builders and WellKnownEndpoints through it so loopback http:// (e.g. the WhoAmI sample's default issuer) is accepted without env-var escape hatches. - AAuthVerifier gains MaxFutureSkew (default 5s); the freshness window for created is now asymmetric (MaxAge backwards, MaxFutureSkew forwards) instead of symmetric MaxAge in both directions. - UseAAuthVerification now resolves AAuthVerifier from DI when none is passed explicitly, honouring DI-registered verifier instances. - AAuthTokenHolder._token marked volatile to document release/acquire semantics for cross-thread token rotation. - WhoAmI sample plumbs AAuth:SignatureWindow config through both the published metadata and the verifier's MaxAge; KeyId/Scope literals hoisted to ResourceKid/ResourceScope constants. - Drop unused NSign.Client + NSign.BouncyCastle packages; reference BouncyCastle.Cryptography 2.6.2 directly on src/AAuth/AAuth.csproj. - Add ThreePartyChallenge_Returns401WithResourceToken integration test that bypasses ChallengeHandler and asserts the raw 401 shape + resource_token claim set. - Mark the in-process mock PS in WhoAmIFlowTests with a Phase 3 follow- up TODO to migrate to samples/MockPersonServer/ once it ships. - Sync implementation-plan.md: tick Phase 2 DoD checkboxes, add a Phase 2 self-review hardening subsection, update Phase 1 NuGet pinning + Phase 2 sections to reflect NSign removal, AAuthRequirement parser merge, and AAuthSigningHandler composition.
Phase tags belong in the implementation plan, not in shipped assets that describe the code's current behaviour. The lone surviving reference is the TODO marker on the in-process mock PS in WhoAmIFlowTests, which still points at the work tracked under Phase 3 \u00a73.1.
There was a problem hiding this comment.
Pull request overview
Implements Phase 2 of the .NET AAuth SDK by adding receiver-side verification, discovery/JWKS resolution, and the full three-party challenge/exchange flow with an end-to-end WhoAmI sample and expanded test coverage.
Changes:
- Added inbound RFC 9421 signature verification (
AAuthVerifier+ ASP.NET middleware) and token verification (TokenVerifierwith JWKS/metadata discovery). - Implemented resource/auth token issuance and the three-party challenge → exchange → retry flow (agent + server components).
- Added WhoAmI sample plus extensive unit, conformance, and integration tests; updated solution and docs accordingly.
Show a summary per file
| File | Description |
|---|---|
| tests/AAuth.Tests/Tokens/TokenVerifierTests.cs | Unit tests for token verification happy/negative paths. |
| tests/AAuth.Tests/Tokens/ResourceTokenBuilderTests.cs | Unit tests for resource token claim shape and validation rules. |
| tests/AAuth.Tests/Tokens/AuthTokenBuilderTests.cs | Unit tests for auth token required claims and validation. |
| tests/AAuth.Tests/Integration/WhoAmIFlowTests.cs | In-process end-to-end identity-based + three-party flow integration tests. |
| tests/AAuth.Tests/HttpSig/SignatureKeyParserTests.cs | Unit tests for Signature-Key JWT extraction and cnf.jwk parsing. |
| tests/AAuth.Tests/HttpSig/AAuthVerifierTests.cs | Unit tests for RFC 9421 signing/verifying round-trip and rejection cases. |
| tests/AAuth.Tests/Headers/AAuthRequirementHeaderTests.cs | Unit tests for AAuth-Requirement formatting/parsing. |
| tests/AAuth.Tests/Discovery/MetadataClientTests.cs | Unit tests for metadata URL building and TTL caching behavior. |
| tests/AAuth.Tests/Discovery/JwksClientTests.cs | Unit tests for JWKS kid resolution, caching, and refresh throttling. |
| tests/AAuth.Tests/Agent/AAuthTokenHolderTests.cs | Unit test for mutable carrier-token holder behavior. |
| tests/AAuth.Tests/AAuth.Tests.csproj | Adds WhoAmI project reference and ASP.NET testing package for integration hosting. |
| tests/AAuth.Conformance/ResourceTokens/ResourceTokenStructureTests.cs | Spec-traceable conformance tests for resource token structure requirements. |
| tests/AAuth.Conformance/README.md | Updates Phase 2 scope and section→file mapping for conformance suite. |
| tests/AAuth.Conformance/HttpSignatures/SignatureKeyHeaderTests.cs | Conformance coverage for Signature-Key header requirements. |
| tests/AAuth.Conformance/HttpSignatures/CoveredComponentsTests.cs | Conformance coverage for covered-component set and created freshness behavior. |
| tests/AAuth.Conformance/Discovery/WellKnownMetadataTests.cs | Conformance coverage for resource discovery metadata + JWKS endpoints. |
| tests/AAuth.Conformance/AgentTokens/AgentTokenVerificationTests.cs | Conformance coverage for verifier-side agent token verification clauses. |
| tests/AAuth.Conformance/AgentTokens/AgentTokenStructureTests.cs | Updates notes to reflect verifier-side conformance now exists. |
| tests/AAuth.Conformance/AAuth.Conformance.csproj | Adds ASP.NET testing dependency for in-process endpoint hosting. |
| src/AAuth/Tokens/TokenVerifier.cs | Implements EdDSA JWT verification and JWKS-based key resolution flow. |
| src/AAuth/Tokens/ResourceTokenBuilder.cs | Implements resource token minting with claim/URL/lifetime validation. |
| src/AAuth/Tokens/JwtWriter.cs | Shared compact JWS assembly/signing helper for token builders. |
| src/AAuth/Tokens/AuthTokenBuilder.cs | Implements auth token minting with required-claim and lifetime validation. |
| src/AAuth/Tokens/AgentTokenBuilder.cs | Aligns URL validation to loopback-friendly helper and updates remarks. |
| src/AAuth/Server/WellKnownEndpoints.cs | Adds endpoint mappers for resource metadata and JWKS well-known docs. |
| src/AAuth/HttpSig/SignatureKeyParser.cs | Parses Signature-Key header and extracts cnf.jwk public key. |
| src/AAuth/HttpSig/SignatureKeyHeader.cs | Formats/parses Signature-Key structured-field value for JWT carrier tokens. |
| src/AAuth/HttpSig/AAuthVerifier.cs | Verifies the AAuth RFC 9421 signature base and created freshness window. |
| src/AAuth/HttpSig/AAuthVerificationMiddleware.cs | ASP.NET middleware to enforce signature verification and expose parsed token. |
| src/AAuth/HttpSig/AAuthSigningHandler.cs | Updates remarks around structured-field behavior and intermediaries. |
| src/AAuth/Headers/AAuthRequirementHeader.cs | Formats/parses AAuth-Requirement challenge header values. |
| src/AAuth/Discovery/MetadataClient.cs | Adds cached well-known metadata fetcher. |
| src/AAuth/Discovery/JwksClient.cs | Adds cached/rate-limited JWKS fetcher and kid resolution. |
| src/AAuth/Crypto/KeyStore.cs | Updates remarks (Windows restriction wording). |
| src/AAuth/Agent/TokenExchangeClient.cs | Implements PS token exchange request/response handling. |
| src/AAuth/Agent/ChallengeHandler.cs | Adds 401 challenge handling, exchange, carrier-token swap, and retry. |
| src/AAuth/Agent/AAuthTokenHolder.cs | Adds mutable carrier token holder used across signing and challenge handlers. |
| src/AAuth/AAuthUrl.cs | Centralized URL validation allowing https plus loopback http for local dev. |
| src/AAuth/AAuth.csproj | Switches to direct BouncyCastle dependency and adds ASP.NET shared framework reference. |
| samples/WhoAmI/WhoAmI.csproj | Converts sample to ASP.NET Core web SDK and references AAuth library. |
| samples/WhoAmI/Program.cs | Implements WhoAmI resource server: discovery, signature verification, challenge, and auth-token verification. |
| samples/AgentConsole/Program.cs | Extends console agent to support --ps and automatic three-party exchange flow. |
| README.md | Rewrites docs to reflect Phase 2 capabilities, samples, and testing commands. |
| hello-world/Program.cs | Removes obsolete placeholder project source. |
| AAuth.slnx | Adds WhoAmI sample to the solution. |
| .devcontainer/post-create.sh | Adds idempotent bash completion + git prompt setup for the devcontainer. |
| .devcontainer/Dockerfile | Installs bash-completion in the devcontainer image. |
| .agent/plans/2026-05-13-dotnet-aauth-sdk/implementation-plan.md | Updates Phase 2 decisions/DoD and records self-review hardening outcomes. |
Copilot's findings
- Files reviewed: 48/48 changed files
- Comments generated: 11
- AAuthVerificationMiddleware: UseAAuthVerification now resolves AAuthVerifier from app.ApplicationServices (with a default-instance fallback) instead of relying on UseMiddleware to bind the dependency, matching the documented behaviour. - TokenVerifier: align the iss URL policy with AAuthUrl.IsHttpsOrLoopback (so loopback issuers accepted by the builders also verify) and validate iss + discovered jwks_uri BEFORE any HTTP call to close the SSRF surface flagged in review. - MetadataClient.FetchAsync: deep-clone the cached JsonObject on every return so a mutating consumer can't poison the shared cache entry. - WhoAmI sample: wrap AAuthKey.FromJwk(cnf) in try/catch and emit a 401 invalid_auth_token response on malformed cnf.jwk instead of a 500. - ChallengeHandler: parse each AAuth-Requirement header value independently and select the first usable auth-token requirement, instead of comma-joining (which AAuthRequirementHeader.Parse rejects). - ResourceTokenBuilder / AuthTokenBuilder: add explicit null guards on Key (and AgentConfirmationKey) so reflection/default! callers see a clear InvalidOperationException rather than NullReferenceException. - README: fix aa-rsrc+jwt -> aa-resource+jwt typo for the resource token media type. - implementation-plan.md: correct the well-known mapper name to MapAAuthResourceWellKnown and note that AAuthRequirementHeader uses a hand-rolled parser (not StructuredFieldValues). - AAuth.Conformance.csproj: swap Microsoft.AspNetCore.Mvc.Testing for the lighter Microsoft.AspNetCore.TestHost package since only TestHost APIs (UseTestServer/GetTestServer) are used.
- TokenExchangeClient: validate the PS-advertised token_endpoint with AAuthUrl.IsHttpsOrLoopback AND pin it to the same origin as the configured personServer before POSTing. Prevents a malicious or compromised PS metadata document from redirecting the signed exchange to an arbitrary host or downgrading it to plain http. - TokenVerifier.VerifyWithJwksAsync: move the cheap, locally-verifiable invariants (alg, typ, dwk) ahead of MetadataClient.FetchAsync / JwksClient.ResolveKeyAsync so obviously-invalid tokens fail fast without triggering outbound discovery calls.
dickhardt
reviewed
May 18, 2026
Contributor
dickhardt
left a comment
There was a problem hiding this comment.
I read over the top level material, LGTM!
I'm not a .NET expert -- so have no opinion on the implementation.
Let us know when you are ready to have links to the libraries -- or create a PR in the www repo!
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.
Phase 2: .NET AAuth SDK — Resource server, verification, and three-party flow
Implements Phase 2 of the .NET AAuth SDK implementation plan. Phase 1 covered issuer-side primitives (keys, agent JWT, outbound RFC 9421 signing). Phase 2 adds receiver-side verification, resource/auth token issuance, discovery, and the full three-party challenge/exchange flow, plus a working WhoAmI sample.
SDK additions (
src/AAuth/)AAuthVerifier,AAuthVerificationMiddleware,SignatureKeyParserResourceTokenBuilder,AuthTokenBuilder,TokenVerifier(sync +VerifyWithJwksAsync)AAuthRequirementHeaderMetadataClient,JwksClient(with caching + rate limiting),WellKnownEndpoints.MapAAuthResourceWellKnownAAuthTokenHolder,TokenExchangeClient,ChallengeHandlerEdDSA JWT signing/verification is implemented via BouncyCastle (native EdDSA isn't available on this .NET 10 runtime).
Samples
samples/WhoAmI/— new ASP.NET Core minimal API that serves/.well-known/aauth-resource.json+/.well-known/jwks.json, verifies inbound signatures, mints aresource_tokenand returns401 AAuth-Requirementwhen an agent token lacks the required person delegation, and returns200+ claims when a valid PS-issued auth token is presented.samples/AgentConsole/— extended with--ps <url>to drive the full three-party flow viaChallengeHandler.Tests
tests/AAuth.Tests/— 92 tests covering every new public type plusIntegration/WhoAmIFlowTests.cs, which usesWebApplicationFactory<Program>to host both WhoAmI and a mock PS in-process and routes traffic between them with a host-based message handler. Covers both identity-based and full three-party paths.tests/AAuth.Conformance/— 5 new spec-traceable test files for agent-token verification,Signature-Keyheader, RFC 9421 covered components, resource-token structure, and discovery endpoints. README section→file map updated.Final run:
Passed: 139, Failed: 0(92 SDK + 47 conformance).Other changes
AAuth.slnxupdated to includesamples/WhoAmI.README.mdrewritten with Phase 2 status banner, four-party primer, SDK component table, sample run instructions (identity-based + three-party), and a Testing section.hello-world/placeholder project.How to try it