Preflight checklist
Describe the bug
HandleOAuth2DeviceAuthorizationRequest reads control parameters such as device_verifier and client_id directly from r.URL.Query(), but later assigns ar.Form = r.Form without first parsing the GET request form.
For a GET request, r.Form is not populated until ParseForm is called. As a result, authorization parameters carried by /oauth2/device/verify, including prompt=login and max_age=0, are absent from the synthetic authorization request. requestAuthentication therefore may reuse a remembered login session instead of requiring fresh authentication.
Reproducing the bug
- Complete a device authorization flow and accept the login with
remember=true, using a browser client that retains Hydra's session cookie.
- Start a second device authorization flow for the same client.
- Open the second
verification_uri_complete with &prompt=login&max_age=0 appended.
- Inspect the second login request.
Actual result: the second login request can have skip=true, and the resulting ID token can retain the earlier authentication time.
Expected result: the query parameters are propagated to the authorization request, so prompt=login causes the second login request to have skip=false and produces a fresh authentication time.
Proposed fix
Populate the synthetic authorization request from the verification request query:
A regression test can run two device flows with the same cookie jar, add prompt=login&max_age=0 to the second verification URL, and assert that both login requests are non-skipped.
Relevant log output
No specific error is logged. The observable symptom is skip=true on the second login request and an unchanged auth_time in the resulting ID token.
Version
Confirmed on Hydra v25.4.0 and still present on master at 4174065ff.
Environment
- OS: Linux
- Deployment: self-hosted Kubernetes
Additional context
A downstream build with the one-line change and the regression test was exercised through a real device login and reauthentication flow. The patched build produced a new authentication time at the explicit reauthentication event and atomically rotated the relying application's session as expected.
AI assistance disclosure: OpenAI Codex was used to inspect the code path, draft this report, and help prepare the regression test. The behavior and proposed fix were independently exercised against a self-hosted deployment.
Preflight checklist
Describe the bug
HandleOAuth2DeviceAuthorizationRequestreads control parameters such asdevice_verifierandclient_iddirectly fromr.URL.Query(), but later assignsar.Form = r.Formwithout first parsing the GET request form.For a GET request,
r.Formis not populated untilParseFormis called. As a result, authorization parameters carried by/oauth2/device/verify, includingprompt=loginandmax_age=0, are absent from the synthetic authorization request.requestAuthenticationtherefore may reuse a remembered login session instead of requiring fresh authentication.Reproducing the bug
remember=true, using a browser client that retains Hydra's session cookie.verification_uri_completewith&prompt=login&max_age=0appended.Actual result: the second login request can have
skip=true, and the resulting ID token can retain the earlier authentication time.Expected result: the query parameters are propagated to the authorization request, so
prompt=logincauses the second login request to haveskip=falseand produces a fresh authentication time.Proposed fix
Populate the synthetic authorization request from the verification request query:
A regression test can run two device flows with the same cookie jar, add
prompt=login&max_age=0to the second verification URL, and assert that both login requests are non-skipped.Relevant log output
No specific error is logged. The observable symptom is
skip=trueon the second login request and an unchangedauth_timein the resulting ID token.Version
Confirmed on Hydra
v25.4.0and still present onmasterat4174065ff.Environment
Additional context
A downstream build with the one-line change and the regression test was exercised through a real device login and reauthentication flow. The patched build produced a new authentication time at the explicit reauthentication event and atomically rotated the relying application's session as expected.
AI assistance disclosure: OpenAI Codex was used to inspect the code path, draft this report, and help prepare the regression test. The behavior and proposed fix were independently exercised against a self-hosted deployment.