DCR: accept every grant type discovery advertises

Discovery advertised the device_code grant in grant_types_supported, but dynamic
client registration only allowed authorization_code/refresh_token, so a client
listing the device grant in its RFC 7591 metadata was rejected with
invalid_client_metadata.

Introduce a single source of truth — OidcController::SUPPORTED_GRANT_TYPES —
used by discovery (grant_types_supported) and by registration validation, so
advertisement and registration can never drift. The token dispatcher already
handles exactly these grants for all clients (they are user-context grants gated
by consent + user_allowed?, so there is no per-client grant restriction), making
advertisement, registration, and enforcement consistent.

Tests: a client registering with the device_code grant now succeeds, plus an
assertion that registration's accepted set equals discovery's advertised set.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7cwhwDJp3MJJDoNPVE6zq
This commit is contained in:
Dan Milne
2026-07-19 13:59:35 +10:00
co-authored by Claude Opus 4.8
parent 71ee301dd2
commit 7eddea8356
3 changed files with 41 additions and 4 deletions
@@ -89,6 +89,25 @@ class OidcRegistrationControllerTest < ActionDispatch::IntegrationTest
assert_equal "invalid_client_metadata", JSON.parse(@response.body)["error"]
end
test "registers a client requesting the device_code grant advertised in discovery" do
enable_dcr
register(
redirect_uris: ["https://client.example.com/cb"],
token_endpoint_auth_method: "none",
grant_types: ["urn:ietf:params:oauth:grant-type:device_code", "refresh_token"]
)
assert_response :created
assert_includes JSON.parse(@response.body)["grant_types"], "urn:ietf:params:oauth:grant-type:device_code"
end
test "registration accepts exactly the grant types discovery advertises" do
get "/.well-known/openid-configuration"
advertised = JSON.parse(@response.body)["grant_types_supported"]
# Single source of truth: what we advertise is what registration accepts.
assert_equal OidcController::SUPPORTED_GRANT_TYPES, advertised
assert_includes advertised, "urn:ietf:params:oauth:grant-type:device_code"
end
test "rejects a non-JSON body" do
enable_dcr
post "/oauth/register", params: "not json", headers: JSON_HEADERS