Skip to content

Fix metadata endpoint 500 with custom controllers outside the doorkeeper namespace - #1854

Merged
nbulaj merged 2 commits into
doorkeeper-gem:mainfrom
55728:fix/metadata-custom-controller-url
Jul 15, 2026
Merged

Fix metadata endpoint 500 with custom controllers outside the doorkeeper namespace#1854
nbulaj merged 2 commits into
doorkeeper-gem:mainfrom
55728:fix/metadata-custom-controller-url

Conversation

@55728

@55728 55728 commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

The RFC 8414 metadata endpoint added in #1838 raises ActionController::UrlGenerationError (HTTP 500) for any application that customizes a controller through use_doorkeeper with a name whose namespace depth differs from doorkeeper/metadata:

Rails.application.routes.draw do
  use_doorkeeper do
    controllers tokens: "custom_tokens"
  end
end
GET /.well-known/oauth-authorization-server
=> ActionController::UrlGenerationError:
   No route matches {action: "create", controller: "doorkeeper/custom_tokens"}

Root cause

MetadataResponse#endpoint_for passes the routes mapping's controller name to url_for unanchored. Rails' URL generation (use_relative_controller!, present since Rails 3) resolves an unanchored controller relative to the current controller's namespace whenever the target has fewer path segments. Since the document is served from doorkeeper/metadata (2 segments), a top-level custom controller like custom_tokens (1 segment) is rewritten to doorkeeper/custom_tokens, which has no route. The inverse also holds: a metadata controller nested deeper than the defaults (e.g. metadata: "admin/oauth/metadata") breaks URL generation for every other endpoint.

The existing specs never hit this because custom_controller_routes_spec.rb gives all controllers (including metadata) names of the same depth, and only asserts route recognition — the metadata response body is never rendered there.

Fix

Prefix the controller name with a slash. The leading slash disables Rails' relative controller resolution and is stripped back out during generation, so default configurations are unaffected:

url_for(controller: "/#{mapping[:controllers]}", action: action)

MetadataResponse#endpoint_for passed the routes mapping's controller name
to url_for unanchored. Rails' URL generation resolves an unanchored
controller relative to the current controller's namespace whenever the
target has fewer path segments, so serving the RFC 8414 document from
doorkeeper/metadata rewrote a configured top-level controller such as
`controllers tokens: "custom_tokens"` into "doorkeeper/custom_tokens"
and raised ActionController::UrlGenerationError (HTTP 500). The inverse
also held: a metadata controller nested deeper than the other endpoints
broke every endpoint's URL.

Prefix the controller name with a slash, which disables the relative
resolution and is stripped back out by URL generation.

The regression spec redraws the app routes with a custom tokens
controller per example rather than in before(:all): route drawing
consults Doorkeeper.config (allow_token_introspection gates the
introspect route), and before(:all) runs ahead of the suite's global
config-reset hook, so it would draw against whatever configuration the
previous randomly-ordered example left behind (reproducible with
--seed 55878).
@55728
55728 force-pushed the fix/metadata-custom-controller-url branch from 5fd8358 to 365da98 Compare July 15, 2026 10:41
@nbulaj
nbulaj requested a review from Copilot July 15, 2026 11:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request fixes a Rails URL generation edge case in Doorkeeper’s RFC 8414 Authorization Server Metadata response, where custom controller mappings whose namespace depth differs from doorkeeper/metadata could trigger ActionController::UrlGenerationError (500) when rendering the metadata document.

Changes:

  • Anchor controller names passed to url_for in Doorkeeper::OAuth::MetadataResponse#endpoint_for by prefixing with a leading slash to avoid Rails’ relative controller resolution.
  • Add a request spec regression test covering a custom tokens controller outside the doorkeeper/* namespace.
  • Document the user-visible fix in CHANGELOG.md.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
lib/doorkeeper/oauth/metadata_response.rb Anchors controller names in url_for to prevent namespace-relative controller resolution from breaking metadata URL generation.
spec/requests/endpoints/metadata_spec.rb Adds regression coverage for custom controller namespace-depth mismatch; redraws routes for the example.
CHANGELOG.md Adds an entry describing the fix for metadata endpoint 500s with custom controllers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread spec/requests/endpoints/metadata_spec.rb
@55728
55728 force-pushed the fix/metadata-custom-controller-url branch from 365da98 to 3d196e9 Compare July 15, 2026 11:24
@nbulaj
nbulaj requested a review from Copilot July 15, 2026 11:26
The routing specs set Rails.application.routes.disable_clear_and_finalize
to true for the duration of the group but never restored it, leaking the
flag to the rest of the suite. Capture the original value and restore it
before reloading the dummy routes, so the reload runs with the original
(normally false) value and finalizes the route set again.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

@nbulaj nbulaj left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 thanks!

@nbulaj
nbulaj merged commit 8839c58 into doorkeeper-gem:main Jul 15, 2026
22 checks passed
@55728
55728 deleted the fix/metadata-custom-controller-url branch July 15, 2026 12:35
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.

3 participants