ory/hydra · error
device_challenge is required
Error message
device_challenge is required
What it means
The device-flow local UI (deviceSrv.GETdevice) serves the user-code page and requires the device_challenge query parameter to build the accept URL later. When it is missing, the handler responds 400 'device_challenge is required'.
Source
Thrown at cmd/cmd_perform_device_flow.go:159
d := deviceSrv{cl: cl, mux: http.NewServeMux()}
d.mux.HandleFunc("GET /device", d.GETdevice)
d.mux.HandleFunc("POST /device", d.POSTdevice)
d.mux.HandleFunc("GET /device/done", d.GETdone)
return &d
}
type deviceSrv struct {
cl *openapi.APIClient
mux *http.ServeMux
}
func (s *deviceSrv) ServeHTTP(w http.ResponseWriter, r *http.Request) {
s.mux.ServeHTTP(w, r)
}
func (s *deviceSrv) GETdevice(w http.ResponseWriter, r *http.Request) {
if r.URL.Query().Get("device_challenge") == "" {
http.Error(w, "device_challenge is required", http.StatusBadRequest)
return
}
err := userCodeTemplate.Execute(w, userCodeData{
UserCode: r.URL.Query().Get("user_code"),
DeviceChallenge: r.URL.Query().Get("device_challenge"),
})
if err != nil {
http.Error(w, fmt.Sprintf("Failed to render template: %s", err), http.StatusInternalServerError)
return
}
}
func (s *deviceSrv) POSTdevice(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
http.Error(w, fmt.Sprintf("Failed to parse form: %s", err), http.StatusBadRequest)
return
}View on GitHub (pinned to 4174065ffb)
Solutions
- Open the URL exactly as returned in verification_uri_complete (or append the device_challenge query param yourself)
- Re-run the device flow login to obtain a fresh device challenge and verification URL
- Check that the browser/QR scanner did not strip the query string
- Ensure nothing in the environment (proxy, redirect) rewrites the URL
Example fix
// before
browser.Open("http://localhost:4445/device")
// after
browser.Open(fmt.Sprintf("http://localhost:4445/device?device_challenge=%s&user_code=%s",
url.QueryEscape(challenge), url.QueryEscape(userCode))) Defensive patterns
Strategy: validation
Validate before calling
// client side: build the URL with the challenge before opening
if deviceChallenge == "" {
return errors.New("device challenge missing; rerun the device flow")
}
verifyURL := fmt.Sprintf("%s?device_challenge=%s", verifyBase, url.QueryEscape(deviceChallenge)) Prevention
- Always open verification_uri_complete returned by Hydra, never a hand-typed URL
- URL-encode query parameters when constructing verification links
- Check QR codes / terminals preserve the full query string
- Regenerate the challenge if it may have expired
When it happens
Trigger: Opening the device verification URL without appending ?device_challenge=..., or with an empty value, as produced by Hydra's device authorization response (verification_uri_complete).
Common situations: User manually typing the verification URL from docs instead of using verification_uri_complete; URL truncation by a terminal/QR-code scanner; the CLI skipping the device_challenge query param when opening the browser; proxy or link shortener stripping query parameters.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- user_code is required
- Token used before issued
- Token is not valid yet
- errKeyNotFound
- unsupported auth type %q
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/f3fb0aaf76c2b222.
Report an issue: GitHub.