Skip to content

disable device code endpoint if not granted - #6

Merged
pascal-fischer merged 1 commit into
masterfrom
fix/disable-device-code-enpoting-if-not-granted
Jul 16, 2026
Merged

disable device code endpoint if not granted#6
pascal-fischer merged 1 commit into
masterfrom
fix/disable-device-code-enpoting-if-not-granted

Conversation

@pascal-fischer

@pascal-fischer pascal-fischer commented Jul 16, 2026

Copy link
Copy Markdown

Summary

Dex lets operators restrict which grants a server supports via oauth2.grantTypes (Config.AllowedGrantTypes). A common hardening step is to remove the
device authorization grant (urn:ietf:params:oauth:grant-type:device_code, RFC 8628) to prevent device-code phishing.

Today that setting does not actually disable the device flow. Removing device_code from AllowedGrantTypes only:

  • drops device_code from discovery (grant_types_supported), and
  • makes the main /token endpoint reject grant_type=device_code.

But the device endpoints themselves — /device, /device/code, /device/auth/verify_code, /device/token, /device/callback — are registered unconditionally,
and none of their handlers consult supportedGrantTypes. In particular, the deprecated /device/token endpoint calls handleDeviceToken directly and never
passes through the grant-type check that /token enforces.

Net effect: an operator who disables the device grant still exposes a fully functional device flow and can still have tokens minted through it — a silent
bypass of a security control.

Why it's still exploitable with the grant "removed"

The only enforcement point for grant types is in handleToken (s.supportedGrantTypes check). The device-flow handlers don't share it:

  • /device/code (handleDeviceCode) still mints a user_code/device_code.
  • /device (handleDeviceExchange) still renders the verification page and drives the browser auth + callback that stores the token.
  • /device/token (handleDeviceTokenDeprecated → handleDeviceToken) still returns the signed token for an approved device_code, without checking
    supportedGrantTypes.

So a client that just avoids the "blocked" /token path and polls the legacy /device/token path completes the whole flow.

Exploit — device-code phishing (unauthenticated attacker)

  1. Attacker POST /device/code with a public client_id → receives user_code + verification_uri_complete. (No client secret; works even with the grant
    "disabled".)
  2. Attacker sends the verification link to a victim. It's the IdP's real domain and real login page.
  3. Victim authenticates and approves the code.
  4. Attacker polls POST /device/token (grant_type=device_code, the attacker's device_code) → receives a valid, IdP-signed ID/access token for the victim's
    identity.

No attacker-controlled redirect URI, no credentials, no client secret — the attacker only needs a registered public client id (device-flow clients are public by design).

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Device-related endpoints are now registered only when the device code grant is supported. Integration tests verify that these routes return 404 when disabled and remain accessible with the default device-grant configuration.

Changes

Device grant endpoint gating

Layer / File(s) Summary
Conditional route registration and integration coverage
server/server.go, server/server_test.go
Device exchange, verification, code, deprecated token, and callback routes are gated by grantTypeDeviceCode; tests verify disabled routes return 404 and enabled routes do not.

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

I’m a rabbit with routes in a row,
Device paths now know when to show.
Grant given? Hop through!
Grant missing? 404!
Tests watch every endpoint glow.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: gating device code endpoints when the grant is not allowed.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/disable-device-code-enpoting-if-not-granted

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pascal-fischer
pascal-fischer merged commit a163de3 into master Jul 16, 2026
3 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants