fix: ignore unrecognized parameters at the token endpoint - #29139
Conversation
…en endpoint OAuth 2.1 §3.2 says the token endpoint must ignore parameters it does not recognize. Ours rejected them with a 400, so a client sending nonce or client_assertion failed here while the same request passed at /oauth2/authorize. Remove the excess-parameter check and log the ignored names at debug, as the authorize endpoint already does. Values are not logged because some of these parameters are credentials. Repeated known parameters are still rejected. One trade-off: a misspelled optional parameter like redirect_url is now silently ignored instead of returning a named 400. The debug log covers that.
|
/coder-agents-review |
|
Chat: Review in progress (15/15 reviewers complete) | View chat deep-review v0.9.0 | Round 1 | Last posted: Round 1, 4 findings (1 Nit, 3 Note), COMMENT. Review Finding inventoryFinding inventory - PR #29139Findings
Contested and acknowledgedNone. Round logRound 1Netero clean (no findings). Panel of 14: bisky, hisoka, mafu-san, mafuuu, pariston, kurapika, chopper, ging-go, gon, leorio, kite, komugi + wildcards zoro, razor. No P0-P4. Two convergent Nits (comment overclaim, commit subject length) and three Notes recording bounded tradeoffs. Mafuuu raised a About deep-reviewCRF = Coder Review Finding (P0-P4, Nit, Note)
|
There was a problem hiding this comment.
Clean, tightly scoped fix: the token endpoint stops rejecting unrecognized form parameters and reuses the existing ignoredParams helper so /oauth2/tokens now matches /oauth2/authorize (RFC 6749 §3.2, OAuth 2.1 §3.2). 95% of the diff is tests, and they are honest tests. TestOAuth2TokenUnrecognizedParametersIgnored redeems the issued token against /users/me instead of settling for the absence of a 400, so a handler that silently dropped the whole request would fail. TestOAuth2TokenRepeatedParameterRejected pins all nine read parameters and documents that the observed error codes diverge from RFC 6749 §5.2 so a later dispatch fix surfaces as a test diff. The debug log carries parameter names only, and the log test asserts the credential values never reach the sink.
Severity count: 0 P0-P4, 2 Nits, 3 Notes. Nothing blocks merge.
The panel tried hard to find a real defect and could not. Pariston: "I tried to build a case that the wrong thing is being fixed and could not." The one concern with a security dimension, a misspelled resource dropping the RFC 8707 audience binding (Mafuuu), does not materialize: authorizationCodeGrant (tokens.go:441-452) fails the exchange with invalid_target when the code was bound to a resource and the token request omits it, so no broadened-audience token is issued. The silent-ignore tradeoff is confined to genuinely optional, non-security parameters and is disclosed in the PR body.
Process note (Nit, CRF-2): the commit and PR subject fix(coderd/oauth2provider): ignore unrecognized parameters at the token endpoint is 80 columns, past the 72-char git convention, so it truncates in git log --oneline. The required scope path eats 27 columns, so the body is fine; only the whole line overruns. Not CI-enforced. A tighter description such as ignore unknown params at the token endpoint (70) fixes it. The commit body is excellent, do not touch it.
coderd/oauth2provider/tokens.go:261
Note [CRF-4] A client that duplicates a known parameter gets "missing required parameters or is otherwise malformed," which names the wrong problem (Leorio).
This PR makes repeat-rejection a tested, guaranteed behavior (TestOAuth2TokenRepeatedParameterRejected), so the message a client sees on a repeat is now in scope. Send resource twice and you get invalid_request with "The request is missing required parameters or is otherwise malformed": nothing is missing, and the developer burns time auditing required fields before guessing it was the duplicate. The parser already knows the field (parseSingle writes "provided more than once" to p.Errors[i].Detail); the handler discards it at the generic branch. Pre-existing dispatch code and out of this PR's scope, so not a finding, but cheap to fix if anyone touches this branch: surface the field name.
🤖
🤖 This review was automatically generated with Coder Agents.
Documentation CheckThis PR changes user-facing behavior of the public Updates Needed
Automated review via Coder Agents |
Docs previewCheck off each page once it's been reviewed. If a page changes in a later push, its checkbox clears automatically so it gets a fresh look. Pages not yet wired into the docs navigation aren't listed here. |
… token parameters A repeated redirect_uri, refresh_token, resource, or scope falls through to the generic invalid_request message, which does not name the field. Co-Authored-By: Claude Fable 5.1 <[email protected]>
…-unrecognized-params
…-unrecognized-params # Conflicts: # coderd/oauth2provider/tokens.go # coderd/oauth2provider/tokens_internal_test.go
TL;DR
The token endpoint rejected any form parameter it did not recognize. OAuth 2.1 §3.2 says it must ignore them. #28736 fixed this for
/oauth2/authorizebut left/oauth2/tokensalone, so a client sendingnonceorclient_assertionto both was accepted at one and refused at the other.redirect_urlis now silently ignored instead of getting a 400. The debug log is where it shows up.No new endpoints, no schema change. Nothing outside
coderd/oauth2providerchanges.Refs #28736
Closes https://linear.app/codercom/issue/PLAT-577
🤖 Generated with Claude Code