fix(devices): pairing claim accepts urlencoded htmx form posts

The browser's Pair device button submits an application/x-www-form-
urlencoded <form> (htmx), but PairingCodeRequest/CancelRegistration-
Request carried only json: tags. Echo v5 routes form posts to the
'form:' binder, which maps by the form: struct tag exclusively — the
code arrived empty, normalized to "", and every browser claim failed
with the generic 'invalid pairing code' 400 even though the separate
lookup step (which reads c.FormValue directly, no struct) had just
resolved the same code. The API clients (plugin, Android, tests) post
JSON and were never affected.

Both request structs now carry dual form:/json: tags, matching the
auth.go convention. Adds TestPairingClaimAcceptsBrowserFormEncoding to
pin the form path: form-encoded lookup resolves, form-encoded claim
binds, device poll delivers credentials.

Found by the user clicking through the real Add Device modal; the
integration suite missed it because every prior claim test posted
application/json.
This commit is contained in:
John O'Keefe committed 2026-11-02 17:12:15 -05:00
1 parent d15f115505
commit 0c31e9b88d
2 files changed
+54 -2

No files matched your search

+4 -2
View File
@@ -104,7 +104,9 @@ type DeviceApprovalRequest struct {
// PairingCodeRequest carries the 6-digit code shown on a registering
// device's screen — the claim credential for the pairing flow.
type PairingCodeRequest struct {
PairingCode string `json:"pairing_code"`
// form tag mirrors json: htmx posts urlencoded, the API posts JSON —
// echo v5's form binder maps by `form:` tag only (auth.go convention).
PairingCode string `form:"pairing_code" json:"pairing_code"`
}
// PairingLookupResponse describes a live registration without binding it —
@@ -117,7 +119,7 @@ type PairingLookupResponse struct {
}
type CancelRegistrationRequest struct {
RegistrationID string `json:"registration_id" validate:"required"`
RegistrationID string `form:"registration_id" json:"registration_id" validate:"required"`
}
type PendingRegistration struct {