fix(http): bind every occurrence of a repeated query parameter - #4
Merged
Conversation
bindFormParam learned to fill a []string from a repeated parameter, but bindQueryParam kept reading one value through Query. A []string query field therefore took the first occurrence and dropped the rest. That is quieter than it used to be, and worse. Before setFieldValue grew a slice case the same field failed the request outright with "unsupported field type". Now the lone value it does read gets split on commas instead, so the request succeeds carrying less than the caller sent. For an RFC 8707 resource indicator that means an access token scoped to fewer audiences than were asked for, with nothing logged. The query path now mirrors the form path exactly: a repeated parameter is taken verbatim, a lone value still expands on commas the way scope=openid,profile always has, an absent parameter falls back to the default tag, and a required one still reports itself missing. Header parameters have the same shape and are left alone here. Repeated headers are rarer and nothing is waiting on them.
github-actions Bot
added a commit
that referenced
this pull request
Aug 25, 2026
## [1.1.8](v1.1.7...v1.1.8) (2026-08-25) ### Bug Fixes * **http:** bind every occurrence of a repeated query parameter ([#4](#4)) ([6b31905](6b31905))
Contributor
|
🎉 This PR is included in version 1.1.8 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
juicycleff
added a commit
to xraph/authsome
that referenced
this pull request
Aug 25, 2026
xraph/go-utils#4 shipped as v1.1.8. bindQueryParam now fills a []string from every occurrence of a repeated query parameter, the way bindFormParam already did, and a lone value still expands on commas so scope=openid,profile is unaffected. That is the release the previous commit said it was waiting for. The three tests it listed as failing against v1.1.7 pass now, and they fail for the right reason without this bump: two_resources_both_land_on_the_code kept only the first resource, and the two TestTokenResource cases were downstream of the same collapse. Nothing else moves. The spec and all three SDKs regenerate byte-identical, the full suite passes and the linter is quiet, because the code this unblocks was already written and only the dependency was missing.
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.
bindFormParamlearned to fill a[]stringfrom a repeated parameter inv1.1.7.
bindQueryParamdid not, and still reads one value throughQuery, soa
[]stringquery field takes the first occurrence and drops the rest.Why this is worse than the bug it replaced
Before
setFieldValuegrew a slice case, that same field failed the requestoutright with "unsupported field type". Loud, and impossible to miss.
Now the lone value it does read gets split on commas instead, so the request
succeeds carrying less than the caller sent. For an RFC 8707 resource
indicator that means an access token scoped to fewer audiences than were asked
for, with nothing logged and nothing returned to say so. Silent narrowing of an
authorization boundary is the failure mode you least want.
Measured before the change:
resource=a&resource=bbindFormParam["a", "b"]bindQueryParam["a"]What changed
The query path now mirrors the form path, the same branch in the same order:
scope=openid,profilealways hasdefaulttagReusing
isMultiValueTargetandsetSliceFieldValuemeans the two paths cannotdrift apart on what counts as a slice target or how elements get converted.
Seven tests cover those cases, including the one that pins the asymmetry: a
lone
scope=openid,emailsplits, while a repeatedscope=openid&scope=a,bkeeps
a,bwhole. Both failed before the change for the repeated cases andpassed for the rest, so the existing behaviour is nailed down as well as the
new.
Not included
Header parameters have the same shape and the same gap. Repeated headers are
rarer and nothing is waiting on them, so
bindHeaderParamis untouched hererather than changed without a caller to justify it.
Downstream
authsome's OAuth2 authorization endpoint reads
resourceoff the raw requesttoday, purely to work around this. Once this ships it becomes an ordinary
[]stringfield with a query tag, which also puts the parameter in thegenerated OpenAPI document for the first time, and therefore in the generated
clients.