Add the RFC 9449 ath claim to DPoP proofs accompanying an access token - #789
Open
josepharuja wants to merge 1 commit into
Open
Add the RFC 9449 ath claim to DPoP proofs accompanying an access token#789josepharuja wants to merge 1 commit into
josepharuja wants to merge 1 commit into
Conversation
josepharuja
added a commit
to enrichmeai/cistern
that referenced
this pull request
Aug 28, 2026
… the provisional numbers beside it Official row (2026-08-28, unmodified harness, main 75c0281): still 0/0/41, verified by a fresh run — but for the first time the halt is not ours. REGISTER CLIENTS passes; the run stops one step later because the harness client's DPoP proofs carry no ath and RFC 9449 §4.3 obliges us to reject exactly that (one ATH_MISSING in the server log per run). Upstream fix offered: solid-contrib/conformance-test-harness#789, per the owner's ruling to contribute rather than route around. Beside it, clearly fenced as NOT the baseline: the patched-client figures (24/11 MustFeatures, 613/28 MustScenarios) — the measured cost of the one absent claim, and the itemised work queue (#165–#170). The official row moves only on an unmodified-harness run; that is the ratchet's whole value. Rebuilt from a clean worktree: the first cut of this branch was committed from a stale shared checkout and silently carried reverts of #159, #160, #162 and #163 — caught by the pre-merge review, discarded, and the shared checkout is being retired from write duty. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Signed-off-by: josepharuja <joseph.a.aruja@gmail.com>
josepharuja
added a commit
to enrichmeai/cistern
that referenced
this pull request
Aug 28, 2026
… the provisional numbers beside it (#171) Official row (2026-08-28, unmodified harness, main 75c0281): still 0/0/41, verified by a fresh run — but for the first time the halt is not ours. REGISTER CLIENTS passes; the run stops one step later because the harness client's DPoP proofs carry no ath and RFC 9449 §4.3 obliges us to reject exactly that (one ATH_MISSING in the server log per run). Upstream fix offered: solid-contrib/conformance-test-harness#789, per the owner's ruling to contribute rather than route around. Beside it, clearly fenced as NOT the baseline: the patched-client figures (24/11 MustFeatures, 613/28 MustScenarios) — the measured cost of the one absent claim, and the itemised work queue (#165–#170). The official row moves only on an unmodified-harness run; that is the ratchet's whole value. Rebuilt from a clean worktree: the first cut of this branch was committed from a stale shared checkout and silently carried reverts of #159, #160, #162 and #163 — caught by the pre-merge review, discarded, and the shared checkout is being retired from write duty. Signed-off-by: josepharuja <joseph.a.aruja@gmail.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
RFC 9449 §4.3 step 12 requires a DPoP proof presented together with an access token to carry ath — the base64url-encoded SHA-256 of the token's ASCII value (§4.2) — and requires resource servers to verify it. Client.generateDpopToken sets jti, htm, htu and iat; this adds ath, guarded so proofs made before a token exists (the token request itself) are unchanged. JwsUtils.accessTokenHash carries the hashing, tested against the worked example in RFC 9449 §4.3. ClientTest verifies the claim is present on getAuthHeaders' proofs and absent from token-less signRequest proofs. Fixes solid-contrib#767. Fixes solid-contrib#786. Signed-off-by: Joseph Antony Aruja <joseph.a.aruja@gmail.com>
josepharuja
force-pushed
the
add-rfc9449-ath-claim
branch
from
August 28, 2026 02:40
7e56052 to
12a3273
Compare
josepharuja
added a commit
to enrichmeai/cistern
that referenced
this pull request
Aug 28, 2026
…d outbound (#175) Owner directive 2026-08-28, reversing 2026-07-17: no AI co-author trailers from the cutover onward; history unrewritten; outbound contributions carry no AI attribution anywhere (first applied on solid-contrib/conformance-test-harness#789). Signed-off-by: Joseph Antony Aruja <joseph.a.aruja@gmail.com>
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.
Follows up #767 and #786, both of which describe this; posting as a PR with the change and its tests rather than a third issue.
What
RFC 9449 §4.3 step 12 requires a DPoP proof presented together with an access token to carry
ath— the base64url-encoded SHA-256 hash of the token's ASCII value (§4.2) — and requires resource servers to verify it.Client.generateDpopTokencurrently setsjti,htm,htuandiat; this PR addsath, guarded on the client holding an access token, so proofs made before a token exists (the token request itself) are unchanged.JwsUtils.accessTokenHash(String)carries the hashing, with a test pinned to the worked example in RFC 9449 §4.3 (Kz~8mXK1EalYznwH-LC-1fBAo.4Ljp~zsPE_NeO.gxU→fUHyO2r2Z3DZ53EsNrWBb0xWXoaNy59IiKCAqksmQEo).ClientTestgains two cases: the claim is present ongetAuthHeadersproofs and hashes the accompanying token; the claim is absent from token-lesssignRequestproofs.Why it matters, with a measurement
A resource server that implements §4.3 as written must reject a proof with no
ath, so every authenticated request the harness makes falls through to anonymous and the run stops in PREPARE SERVER. We ran the suite (1.2.2, test suite 0.0.19, 41 test cases) twice against the same server build — one that validatesath— changing only this guarded claim in the harness client:athThe gap between the rows is the cost of the one absent claim: the difference between a §4.3-strict implementation receiving no signal at all and receiving an itemised list of real defects to fix. Servers that skip the
athcheck are unaffected by this change — the proof simply carries one additional claim they ignore.Happy to adjust anything about the shape of the change — the hashing could live in
Clientinstead ofJwsUtilsif you prefer it private, and the tests follow the existingmockClientpattern.The harness is the reason a second implementation can measure itself at all — thank you for maintaining it.