[#4253 5/8] feat(auth): two-VP caller seeds SP build via initialBindings (Policy 2)#4287
Draft
stevenvegt wants to merge 1 commit into
Draft
[#4253 5/8] feat(auth): two-VP caller seeds SP build via initialBindings (Policy 2)#4287stevenvegt wants to merge 1 commit into
stevenvegt wants to merge 1 commit into
Conversation
Assisted-by: AI
Contributor
|
Coverage Impact ⬇️ Merging this pull request will decrease total coverage on 🛟 Help
|
This was referenced May 27, 2026
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.

Parent PRD
#4253
Item 5 of 8. Depends on item #4 (#4286) — branched off
4253-4-buildsubmission-bindings. This is where Policy 2 lands and the two-VP behavior actually changes.Summary
The RFC 7523 two-VP token flow stops merging captured organization field values into
credential_selectionand instead passes them as the SP build'sinitialBindings.credential_selectionstays the user's input; the cross-VP capture becomes internal plumbing, as Policy 2 specifies. This cleanly resolves PRD problem #1 (over-strict cross-VP selection) and makes numeric cross-VP ids bind.Implementation Spec
In
auth/client/iam/openid4vp.go,requestJwtBearerAccessToken:orgPD.ResolveConstraintsFields(credentialMap)(line 392).credentialSelection = applyCapturedFieldsToSelection(credentialSelection, captured)merge (line 399).credentialSelectionis no longer mutated — it remains the user's selection.captured(map[string]interface{}) tomap[string]stringand pass it as theinitialBindingsargument to the SP build only. The org build passes nil.applyCapturedFieldsToSelection(472-488) is replaced by acapturedToBindings(captured map[string]any) map[string]stringconverter (no selection merge).Thread the new parameter through
buildSubmissionForSubject(line 449): it gains aninitialBindings map[string]stringargument forwarded towallet.BuildSubmission(line 465). The organization call (line 370) and the single-VP path pass nil; the service-provider call (line 402) passes the converted captured bindings.Stringification (must match Select)
The captured value and the SP candidate's resolved value have to stringify identically or the binding won't match.
Select's binding comparison stringifies string / float64 / bool (the formermatchesSelectionslogic, now insideSelect).capturedToBindingsmust use the same conversion, so expose a small sharedpehelper (e.g.pe.BindingValue(v any) (string, bool)) used by bothSelectand this caller. This also fixes a latent gap: the old merge kept only string-valued captures (skipped numbers), so numeric cross-VP ids never bound; stringifying all matches the PRD'spatient_bsnworked example.Filtering: rely on Select's drop
The full converted captured map is passed as
initialBindings;Selectdrops any key not present as a field id on the SP PD (its single source of truth for accepted keys). No explicit SP-field-id filter in the caller — no duplicated field-id knowledge. The cross-VP binding then works structurally: the SP PD's descriptors that share a capturedidare constrained bySelect's binding consistency (Policy 3), so e.g. the SP delegation's$.issueris forced to equal the HCP'scredentialSubject.id.Why this resolves problem #1
The over-strictness came from
NewFieldSelectorfailing loudly on merged captured keys absent from the SP PD. That selector is gone (#3), and captured values now arrive asinitialBindingsthatSelectsilently drops when not on the SP PD. So a caller that never asked for SP-side filtering on an org-only id is no longer broken.Testing
auth/client/iamtwo-VP chain test:$.issuer);credential_selectionis not mutated by the capture;Acceptance Criteria
applyCapturedFieldsToSelectionmerge removed;credential_selectionno longer mutated by capture.initialBindingsto the SP build (nil for org / single-VP); threaded throughbuildSubmissionForSubject.pehelper withSelect; numeric ids bind.go build ./...andgo test ./auth/... ./vcr/...pass.